<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="generator" content="VNote">

    <title>23_非对称加密</title>
    <link rel="icon" href="https://github.com/tamlok/vnote/raw/master/src/resources/icons/vnote.ico">

    <style type="text/css">
    /* STYLE_GLOBAL_PLACE_HOLDER */
    </style>

    <style type="text/css">
    *,
*::before,
*::after {
  box-sizing: border-box;
}

.container-fluid {
    width: 100%;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

.col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-auto, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-auto, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-auto, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-auto, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto {
    position: relative;
    width: 100%;
    min-height: 1px;
    padding-right: 15px;
    padding-left: 15px;
}

.col-12 {
    -webkit-box-flex: 0;
    -ms-flex: 0 0 100%;
    flex: 0 0 100%;
    max-width: 100%;
}

@media (min-width: 768px) {
    .col-md-3 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 25%;
        flex: 0 0 25%;
        max-width: 25%;
    }
}

@media (min-width: 768px) {
    .col-md-9 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 75%;
        flex: 0 0 75%;
        max-width: 75%;
    }
}

@media (min-width: 1200px) {
    .col-xl-2 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 16.666667%;
        flex: 0 0 16.666667%;
        max-width: 16.666667%;
    }
}

@media (min-width: 1200px) {
    .col-xl-10 {
        -webkit-box-flex: 0;
        -ms-flex: 0 0 83.333333%;
        flex: 0 0 83.333333%;
        max-width: 83.333333%;
    }
}

@media (min-width: 768px) {
    .pt-md-3, .py-md-3 {
        padding-top: 1rem!important;
    }
}

@media (min-width: 768px) {
    .pb-md-3, .py-md-3 {
        padding-bottom: 1rem!important;
    }
}

@media (min-width: 768px) {
    .pl-md-5, .px-md-5 {
        padding-left: 3rem!important;
    }
}

.d-none {
    display: none!important;
}

@media (min-width: 1200px) {
    .d-xl-block {
        display: block!important;
    }
}

@media (min-width: 768px) {
    .d-md-block {
        display: block!important;
    }
}

.bd-content {
    -webkit-box-ordinal-group: 1;
    -ms-flex-order: 0;
    order: 0;
}

.bd-toc {
    position: -webkit-sticky;
    position: sticky;
    top: 4rem;
    height: calc(100vh - 10rem);
    overflow-y: auto;
}

.bd-toc {
    -webkit-box-ordinal-group: 2;
    -ms-flex-order: 1;
    order: 1;
    padding-top: 1.5rem;
    padding-bottom: 1.5rem;
    font-size: .875rem;
}

.section-nav {
    padding-left: 0;
}

.section-nav ul {
    font-size: .875rem;
    list-style-type: none;
}

.section-nav li {
    font-size: .875rem;
}

.section-nav a {
    color: inherit !important;
}

.row {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin-right: -15px;
    margin-left: -15px;
}

@media (min-width: 1200px) {
    .flex-xl-nowrap {
        flex-wrap: nowrap !important;
    }
}

#floating-button {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background: #00897B;
    position: fixed;
    top: .5rem;
    right: .5rem;
    cursor: pointer;
    box-shadow: 0px 2px 5px #666;
}

#floating-button .more {
    color: #F5F5F5;
    position: absolute;
    top: 0;
    display: block;
    bottom: 0;
    left: 0;
    right: 0;
    text-align: center;
    padding: 0;
    margin: 0;
    line-height: 2.5rem;
    font-size: 2rem;
    font-family: 'monospace';
    font-weight: 300;
}

.hide-none {
    display: none !important;
}

.col-expand {
    -webkit-box-flex: 0;
    -ms-flex: 0 0 100% !important;
    flex: 0 0 100% !important;
    max-width: 100% !important;
    padding-right: 3rem !important;
}

.outline-bold {
    font-weight: bolder !important;
}

@media print {
    #floating-button {
        display: none !important;
    }
}

    @keyframes flash { 
  0% { color: rgb(128, 203, 196); }
  10% { color: rgb(0, 137, 123); }
  40% { color: rgb(0, 137, 123); }
  50% { color: rgb(128, 203, 196); }
  60% { color: rgb(0, 137, 123); }
  90% { color: rgb(0, 137, 123); }
}
.highlighted-anchor { animation: flash 1s; }
div.mark-rect { background: transparent; border: 5px solid rgb(87, 104, 196); border-radius: 2px; position: absolute; }
#vnote-footer { width: 100%; text-align: center; opacity: 0.2; margin-top: 3rem; }
#vnote-footer p { font-size: 0.8rem; }
#vnote-footer a { color: inherit !important; }
x-eqs { display: flex; flex-direction: row; align-content: space-between; align-items: center; }
x-eqs > x-eqn { width: 100%; margin-left: 3rem; }
x-eqs > span { text-align: right; }
.view-image, .view-svg { transition: 0.3s; }
.modal-box { display: none; position: fixed; z-index: 1000; padding-top: 50px; left: 0px; top: 0px; width: 100%; height: 100%; overflow: hidden; background-color: rgba(68, 68, 68, 0.952941); }
.modal-content { margin: auto; display: block; width: auto; height: auto; cursor: move; }
.modal-content { animation-name: zoom; animation-duration: 0.6s; }
@-webkit-keyframes zoom { 
  0% { transform: scale(0); }
  100% { transform: scale(1); }
}
@keyframes zoom { 
  0% { transform: scale(0); }
  100% { transform: scale(1); }
}
span.modal-close { position: absolute; z-index: 1000; top: 15px; right: 35px; color: rgb(218, 218, 218); font-size: 40px; font-weight: bold; transition: 0.3s; }
span.modal-close:hover, span.modal-close:focus { color: rgb(238, 238, 238); text-decoration: none; cursor: pointer; }
@media print {
  pre, pre code, td.hljs-ln-code { white-space: pre-wrap !important; word-break: break-all !important; }
  code, a { word-break: break-all !important; }
  div.flowchart-diagram, div.mermaid-diagram, div.plantuml-diagram { overflow: hidden !important; }
  img { max-width: 100% !important; height: auto !important; }
  #vnote-footer { display: none !important; }
}
.alert { position: relative; padding: 0.75rem 1.25rem; margin-bottom: 1rem; border: 1px solid transparent; border-radius: 0.25rem; }
.alert-primary { color: rgb(0, 64, 133); background-color: rgb(204, 229, 255); border-color: rgb(184, 218, 255); }
.alert-secondary { color: rgb(56, 61, 65); background-color: rgb(226, 227, 229); border-color: rgb(214, 216, 219); }
.alert-success { color: rgb(21, 87, 36); background-color: rgb(212, 237, 218); border-color: rgb(195, 230, 203); }
.alert-info { color: rgb(12, 84, 96); background-color: rgb(209, 236, 241); border-color: rgb(190, 229, 235); }
.alert-warning { color: rgb(133, 100, 4); background-color: rgb(255, 243, 205); border-color: rgb(255, 238, 186); }
.alert-danger { color: rgb(114, 28, 36); background-color: rgb(248, 215, 218); border-color: rgb(245, 198, 203); }
.alert-light { color: rgb(129, 129, 130); background-color: rgb(254, 254, 254); border-color: rgb(253, 253, 254); }
.alert-dark { color: rgb(27, 30, 33); background-color: rgb(214, 216, 217); border-color: rgb(198, 200, 202); }
.vnote-anchor { font-weight: 400; color: rgba(0, 123, 255, 0.498039); transition: color 0.16s linear; padding-left: 0.375em; -webkit-font-smoothing: antialiased; text-decoration: none; opacity: 0; }
.vnote-anchor:hover { color: rgb(0, 123, 255); text-decoration: none; opacity: 1; }
.vnote-anchor::after { content: attr(data-anchor-icon); }
.vnote-btn { position: relative; display: inline-block; padding: 6px 12px; font-size: 13px; font-weight: 700; line-height: 20px; white-space: nowrap; vertical-align: middle; cursor: pointer; border: none; user-select: none; -webkit-appearance: none; }
.vnote-copy-clipboard-btn { transition: opacity 0.3s ease-in-out; opacity: 0; padding: 2px 6px; position: absolute; top: 5px; right: 5px; }
pre:hover .vnote-copy-clipboard-btn { opacity: 1; }
pre.vnote-snippet { position: relative; }
body { margin: 0px auto; font-family: "Segoe UI", Helvetica, sans-serif, Tahoma, Arial, Geneva, Georgia, Palatino, "Times New Roman", "Hiragino Sans GB", 冬青黑体, "Microsoft YaHei", 微软雅黑, "Microsoft YaHei UI", "WenQuanYi Micro Hei", 文泉驿雅黑, Dengxian, 等线体, STXihei, 华文细黑, "Liberation Sans", "Droid Sans", NSimSun, 新宋体, SimSun, 宋体; color: rgb(34, 34, 34); line-height: 1.5; padding: 15px; background: rgb(238, 238, 238); font-size: 16px; }
h1, h2, h3, h4, h5, h6 { color: rgb(34, 34, 34); font-weight: bold; margin-top: 20px; margin-bottom: 10px; padding: 0px; }
p { padding: 0px; margin-top: 16px; margin-bottom: 16px; }
h1 { font-size: 26px; }
h2 { font-size: 24px; }
h3 { font-size: 22px; }
h4 { font-size: 20px; }
h5 { font-size: 19px; }
h6 { font-size: 18px; }
a { color: rgb(0, 153, 255); margin: 0px; padding: 0px; vertical-align: baseline; text-decoration: none; word-break: break-word; }
a:hover { text-decoration: underline; color: rgb(255, 102, 0); }
a:visited { color: purple; }
ul, ol { padding: 0px 0px 0px 24px; }
li { line-height: 24px; }
li ul, li ol { margin-left: 16px; }
p, ul, ol { font-size: 16px; line-height: 24px; }
pre { display: block; overflow-y: hidden; overflow-x: auto; tab-size: 4; }
code { font-family: Consolas, Monaco, monospace, Courier; color: rgb(142, 36, 170); word-break: break-word; }
pre code { display: block; overflow-x: auto; padding: 0.5em; color: rgb(34, 34, 34); background-color: rgb(224, 224, 224); border-left: 0.5em solid rgb(0, 137, 123); line-height: 1.5; font-family: Consolas, Monaco, monospace, Courier; white-space: pre; tab-size: 4; }
pre code.markdown-metadata { border-left: 0.5em solid rgb(128, 203, 196); }
aside { display: block; float: right; width: 390px; }
blockquote { color: rgb(102, 102, 102); border-left: 0.5em solid rgb(122, 122, 122); padding: 0px 1em; margin-left: 0px; }
blockquote p { color: rgb(102, 102, 102); }
hr { display: block; text-align: left; margin: 1em 0px; border: none; height: 2px; background: rgb(153, 153, 153); }
table { padding: 0px; margin: 1rem 0.5rem; border-collapse: collapse; }
table tr { border-top: 2px solid rgb(204, 204, 204); background-color: white; margin: 0px; padding: 0px; }
table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }
table tr th { font-weight: bold; border: 2px solid rgb(204, 204, 204); margin: 0px; padding: 6px 13px; }
table tr td { border: 2px solid rgb(204, 204, 204); margin: 0px; padding: 6px 13px; }
table tr th :first-child, table tr td :first-child { margin-top: 0px; }
table tr th :last-child, table tr td :last-child { margin-bottom: 0px; }
div.mermaid-diagram { margin: 16px 0px; overflow-y: hidden; }
div.flowchart-diagram { padding: 0px 5px; margin: 16px 0px; width: fit-content; overflow: hidden; }
div.wavedrom-diagram { padding: 0px 5px; margin: 16px 0px; width: fit-content; overflow: hidden; }
div.plantuml-diagram { padding: 5px 5px 0px; margin: 16px 0px; width: fit-content; overflow: hidden; }
.img-package { text-align: center; }
img.img-center { display: block; margin-left: auto; margin-right: auto; }
span.img-caption { min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid rgb(192, 192, 192); color: rgb(108, 108, 108); text-align: center; line-height: 1.5; }
.emoji_zero, .emoji_one, .emoji_two, .emoji_three, .emoji_four, .emoji_five, .emoji_six, .emoji_seven, .emoji_eight, .emoji_nine { margin-left: 5px; margin-right: 8px; }
div.preview-hint { opacity: 0.5; margin-top: 30%; margin-bottom: 30%; align-items: center; display: flex; flex-direction: column; justify-content: center; }
table.hljs-ln tr { border: none; background-color: transparent; }
table.hljs-ln tr td { border: none; background-color: transparent; }
table.hljs-ln tr td.hljs-ln-numbers { user-select: none; text-align: center; color: rgb(170, 170, 170); border-right: 1px solid rgb(204, 204, 204); vertical-align: top; padding-right: 5px; white-space: nowrap; }
table.hljs-ln tr td.hljs-ln-code { padding-left: 10px; }
::-webkit-scrollbar { background-color: rgb(234, 234, 234); width: 14px; height: 14px; border: none; }
::-webkit-scrollbar-corner { background-color: rgb(234, 234, 234); }
::-webkit-scrollbar-button { height: 14px; width: 14px; background-color: rgb(234, 234, 234); }
::-webkit-scrollbar-button:hover { background-color: rgb(208, 208, 208); }
::-webkit-scrollbar-button:active { background-color: rgb(178, 178, 178); }
::-webkit-scrollbar-track { background-color: rgb(234, 234, 234); }
::-webkit-scrollbar-thumb { border: none; background-color: rgb(218, 218, 218); }
::-webkit-scrollbar-thumb:hover { background-color: rgb(208, 208, 208); }
::-webkit-scrollbar-thumb:active { background-color: rgb(178, 178, 178); }
::-webkit-scrollbar-button:horizontal:increment { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="rotate(-90 256.00000000000006,256) " id="svg_1">   <polygon fill="%23333333" id="svg_2" points="128,192 256,320 384,192  "/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::-webkit-scrollbar-button:horizontal:decrement { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="rotate(90 255.99999999999997,256.00000000000006) " id="svg_1">   <polygon points="128,192 256,320 384,192  " id="svg_2" fill="%23333333"/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::-webkit-scrollbar-button:vertical:increment { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="null" id="svg_1">   <polygon points="128,192 256,320 384,192  " id="svg_2" fill="%23333333"/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::-webkit-scrollbar-button:vertical:decrement { background-image: url('data:image/svg+xml;utf8,<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <g>    <g transform="rotate(180 255.99999999999997,256) " id="svg_1">   <polygon points="128,192 256,320 384,192  " id="svg_2" fill="%23333333"/>  </g> </g></svg>'); background-repeat: no-repeat; background-size: contain; }
::selection { background: rgb(25, 118, 210); color: rgb(238, 238, 238); }
.modal-box { background-color: rgba(234, 234, 234, 0.952941); }
span.modal-close { color: rgb(102, 102, 102); }
span.modal-close:hover, span.modal-close:focus { color: rgb(34, 34, 34); }
.hljs { display: block; overflow-x: auto; padding: 0.5em; background: rgb(224, 224, 224); }
.hljs, .hljs-subst { color: rgb(54, 54, 54); }
.hljs-comment { color: rgb(118, 118, 118); }
.hljs-keyword, .hljs-attribute, .hljs-selector-tag, .hljs-meta-keyword, .hljs-doctag, .hljs-name { color: rgb(0, 0, 238); }
.hljs-type, .hljs-string, .hljs-number, .hljs-selector-id, .hljs-selector-class, .hljs-quote, .hljs-template-tag, .hljs-deletion { color: rgb(136, 0, 0); }
.hljs-title, .hljs-section { color: rgb(136, 0, 0); font-weight: bold; }
.hljs-regexp, .hljs-symbol, .hljs-variable, .hljs-template-variable, .hljs-link, .hljs-selector-attr, .hljs-selector-pseudo { color: rgb(188, 96, 96); }
.hljs-literal { color: rgb(175, 0, 215); }
.hljs-built_in, .hljs-bullet, .hljs-code, .hljs-addition { color: rgb(0, 135, 0); }
.hljs-meta { color: rgb(31, 113, 153); }
.hljs-meta-string { color: rgb(77, 153, 191); }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: bold; }
.mermaid-diagram .mermaid .label { color: rgb(51, 51, 51); }
.mermaid-diagram .node rect, .mermaid-diagram .node circle, .mermaid-diagram .node ellipse, .mermaid-diagram .node polygon { fill: rgb(236, 236, 255); stroke: rgb(204, 204, 255); stroke-width: 1px; }
.mermaid-diagram .edgePath .path { stroke: rgb(51, 51, 51); }
.mermaid-diagram .edgeLabel { background-color: rgb(232, 232, 232); }
.mermaid-diagram .cluster rect { fill: rgb(255, 255, 222) !important; rx: 4 !important; stroke: rgb(170, 170, 51) !important; stroke-width: 1px !important; }
.mermaid-diagram .cluster text { fill: rgb(51, 51, 51); }
.mermaid-diagram .actor { stroke: rgb(204, 204, 255); fill: rgb(236, 236, 255); }
.mermaid-diagram text.actor { fill: black; stroke: none; }
.mermaid-diagram .actor-line { stroke: grey; }
.mermaid-diagram .messageLine0 { stroke-width: 1.5; stroke: rgb(51, 51, 51); }
.mermaid-diagram .messageLine1 { stroke-width: 1.5; stroke: rgb(51, 51, 51); }
.mermaid-diagram #arrowhead { fill: rgb(51, 51, 51); }
.mermaid-diagram #crosshead path { fill: rgb(51, 51, 51) !important; stroke: rgb(51, 51, 51) !important; }
.mermaid-diagram .messageText { fill: rgb(51, 51, 51); stroke: none; }
.mermaid-diagram .labelBox { stroke: rgb(204, 204, 255); fill: rgb(236, 236, 255); }
.mermaid-diagram .labelText { fill: black; stroke: none; }
.mermaid-diagram .loopText { fill: black; stroke: none; }
.mermaid-diagram .loopLine { stroke-width: 2; stroke: rgb(204, 204, 255); }
.mermaid-diagram .note { stroke: rgb(170, 170, 51); fill: rgb(255, 245, 173); }
.mermaid-diagram .noteText { fill: black; stroke: none; font-family: "trebuchet ms", verdana, arial; font-size: 14px; }
.mermaid-diagram .section { stroke: none; opacity: 0.2; }
.mermaid-diagram .section0 { fill: rgba(102, 102, 255, 0.490196); }
.mermaid-diagram .section2 { fill: rgb(255, 244, 0); }
.mermaid-diagram .section1, .mermaid-diagram .section3 { fill: white; opacity: 0.2; }
.mermaid-diagram .sectionTitle0 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle1 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle2 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle3 { fill: rgb(51, 51, 51); }
.mermaid-diagram .sectionTitle { text-anchor: start; font-size: 11px; }
.mermaid-diagram .grid .tick { stroke: lightgrey; opacity: 0.3; shape-rendering: crispEdges; }
.mermaid-diagram .grid path { stroke-width: 0; }
.mermaid-diagram .today { fill: none; stroke: red; stroke-width: 2px; }
.mermaid-diagram .task { stroke-width: 2; }
.mermaid-diagram .taskText { text-anchor: middle; font-size: 11px; }
.mermaid-diagram .taskTextOutsideRight { fill: black; text-anchor: start; font-size: 11px; }
.mermaid-diagram .taskTextOutsideLeft { fill: black; text-anchor: end; font-size: 11px; }
.mermaid-diagram .taskText0, .mermaid-diagram .taskText1, .mermaid-diagram .taskText2, .mermaid-diagram .taskText3 { fill: white; }
.mermaid-diagram .task0, .mermaid-diagram .task1, .mermaid-diagram .task2, .mermaid-diagram .task3 { fill: rgb(138, 144, 221); stroke: rgb(83, 79, 188); }
.mermaid-diagram .taskTextOutside0, .mermaid-diagram .taskTextOutside2 { fill: black; }
.mermaid-diagram .taskTextOutside1, .mermaid-diagram .taskTextOutside3 { fill: black; }
.mermaid-diagram .active0, .mermaid-diagram .active1, .mermaid-diagram .active2, .mermaid-diagram .active3 { fill: rgb(191, 199, 255); stroke: rgb(83, 79, 188); }
.mermaid-diagram .activeText0, .mermaid-diagram .activeText1, .mermaid-diagram .activeText2, .mermaid-diagram .activeText3 { fill: black !important; }
.mermaid-diagram .done0, .mermaid-diagram .done1, .mermaid-diagram .done2, .mermaid-diagram .done3 { stroke: grey; fill: lightgrey; stroke-width: 2; }
.mermaid-diagram .doneText0, .mermaid-diagram .doneText1, .mermaid-diagram .doneText2, .mermaid-diagram .doneText3 { fill: black !important; }
.mermaid-diagram .crit0, .mermaid-diagram .crit1, .mermaid-diagram .crit2, .mermaid-diagram .crit3 { stroke: rgb(255, 136, 136); fill: red; stroke-width: 2; }
.mermaid-diagram .activeCrit0, .mermaid-diagram .activeCrit1, .mermaid-diagram .activeCrit2, .mermaid-diagram .activeCrit3 { stroke: rgb(255, 136, 136); fill: rgb(191, 199, 255); stroke-width: 2; }
.mermaid-diagram .doneCrit0, .mermaid-diagram .doneCrit1, .mermaid-diagram .doneCrit2, .mermaid-diagram .doneCrit3 { stroke: rgb(255, 136, 136); fill: lightgrey; stroke-width: 2; cursor: pointer; shape-rendering: crispEdges; }
.mermaid-diagram .doneCritText0, .mermaid-diagram .doneCritText1, .mermaid-diagram .doneCritText2, .mermaid-diagram .doneCritText3 { fill: black !important; }
.mermaid-diagram .activeCritText0, .mermaid-diagram .activeCritText1, .mermaid-diagram .activeCritText2, .mermaid-diagram .activeCritText3 { fill: black !important; }
.mermaid-diagram .titleText { text-anchor: middle; font-size: 18px; fill: black; }
.mermaid-diagram .node text { font-family: "trebuchet ms", verdana, arial; font-size: 14px; }
.mermaid-diagram div.mermaidTooltip { position: absolute; text-align: center; max-width: 200px; padding: 2px; font-family: "trebuchet ms", verdana, arial; font-size: 12px; background: rgb(255, 255, 222); border: 1px solid rgb(170, 170, 51); border-radius: 2px; pointer-events: none; z-index: 100; }
#mermaid-diagram-1 .node > rect { }
#mermaid-diagram-1 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-1 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-1 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-1 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-2 .node > rect { }
#mermaid-diagram-2 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-2 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-2 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-2 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-3 .node > rect { }
#mermaid-diagram-3 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-3 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-3 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-3 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-4 .node > rect { }
#mermaid-diagram-4 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-4 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-4 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-4 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-5 .node > rect { }
#mermaid-diagram-5 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-5 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-5 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-5 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-6 .node > rect { }
#mermaid-diagram-6 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-6 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-6 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-6 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }
#mermaid-diagram-7 .node > rect { }
#mermaid-diagram-7 .node text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-7 .edgeLabel text { fill: rgb(0, 0, 0); stroke: none; font-weight: 300; font-family: "Helvetica Neue", Helvetica, Arial, sans-serf; font-size: 14px; }
#mermaid-diagram-7 .cluster rect { fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-7 .cyan > rect, .cyan > polygon, .cyan > circle, .cyan > ellipse { fill: rgb(153, 255, 255); stroke: rgb(255, 255, 255); }

    </style>

    <script type="text/javascript">
var toc = [];

var setVisible = function(node, visible) {
    var cl = 'hide-none';
    if (visible) {
        node.classList.remove(cl);
    } else {
        node.classList.add(cl);
    }
};

var isVisible = function(node) {
    var cl = 'hide-none';
    return !node.classList.contains(cl);
};

var setPostContentExpanded = function(node, expanded) {
    var cl = 'col-expand';
    if (expanded) {
        node.classList.add(cl);
    } else {
        node.classList.remove(cl);
    }
};

var setOutlinePanelVisible = function(visible) {
    var outlinePanel = document.getElementById('outline-panel');
    var postContent = document.getElementById('post-content');

    setVisible(outlinePanel, visible);
    setPostContentExpanded(postContent, !visible);
};

var isOutlinePanelVisible = function() {
    var outlinePanel = document.getElementById('outline-panel');
    return isVisible(outlinePanel);
};

window.addEventListener('load', function() {
    var outlinePanel = document.getElementById('outline-panel');
    outlinePanel.style.display = 'initial';

    var floatingContainer = document.getElementById('container-floating');
    floatingContainer.style.display = 'initial';

    var outlineContent = document.getElementById('outline-content');
    var postContent = document.getElementById('post-content');

    // Escape @text to Html.
    var escapeHtml = function(text) {
        var map = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#039;'
        };

        return text.replace(/[&<>"']/g, function(m) { return map[m]; });
    }

    // Fetch the outline.
    var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");
    toc = [];
    for (var i = 0; i < headers.length; ++i) {
        var header = headers[i];

        toc.push({
            level: parseInt(header.tagName.substr(1)),
            anchor: header.id,
            title: escapeHtml(header.textContent)
        });
    }

    if (toc.length == 0) {
        setOutlinePanelVisible(false);
        setVisible(floatingContainer, false);
        return;
    }

    var baseLevel = baseLevelOfToc(toc);
    var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel);

    outlineContent.innerHTML = tocTree;
    setOutlinePanelVisible(true);
    setVisible(floatingContainer, true);
});

// Return the topest level of @toc, starting from 1.
var baseLevelOfToc = function(p_toc) {
    var level = -1;
    for (i in p_toc) {
        if (level == -1) {
            level = p_toc[i].level;
        } else if (level > p_toc[i].level) {
            level = p_toc[i].level;
        }
    }

    if (level == -1) {
        level = 1;
    }

    return level;
};

// Handle wrong title levels, such as '#' followed by '###'
var toPerfectToc = function(p_toc, p_baseLevel) {
    var i;
    var curLevel = p_baseLevel - 1;
    var perfToc = [];
    for (i in p_toc) {
        var item = p_toc[i];

        // Insert empty header.
        while (item.level > curLevel + 1) {
            curLevel += 1;
            var tmp = { level: curLevel,
                        anchor: '',
                        title: '[EMPTY]'
                      };
            perfToc.push(tmp);
        }

        perfToc.push(item);
        curLevel = item.level;
    }

    return perfToc;
};

var itemToHtml = function(item) {
    return '<a href="#' + item.anchor + '" data="' + item.anchor + '">' + item.title + '</a>';
};

// Turn a perfect toc to a tree using <ul>
var tocToTree = function(p_toc, p_baseLevel) {
    var i;
    var front = '<li>';
    var ending = ['</li>'];
    var curLevel = p_baseLevel;
    for (i in p_toc) {
        var item = p_toc[i];
        if (item.level == curLevel) {
            front += '</li>';
            front += '<li>';
            front += itemToHtml(item);
        } else if (item.level > curLevel) {
            // assert(item.level - curLevel == 1)
            front += '<ul>';
            ending.push('</ul>');
            front += '<li>';
            front += itemToHtml(item);
            ending.push('</li>');
            curLevel = item.level;
        } else {
            while (item.level < curLevel) {
                var ele = ending.pop();
                front += ele;
                if (ele == '</ul>') {
                    curLevel--;
                }
            }
            front += '</li>';
            front += '<li>';
            front += itemToHtml(item);
        }
    }
    while (ending.length > 0) {
        front += ending.pop();
    }
    front = front.replace("<li></li>", "");
    front = '<ul>' + front + '</ul>';
    return front;
};

var toggleMore = function() {
    if (toc.length == 0) {
        return;
    }

    var p = document.getElementById('floating-more');
    if (isOutlinePanelVisible()) {
        p.textContent = '<';
        setOutlinePanelVisible(false);
    } else {
        p.textContent = '>';
        setOutlinePanelVisible(true);
    }
};

window.addEventListener('scroll', function() {
    if (toc.length == 0 || !isOutlinePanelVisible()) {
        return;
    }

    var postContent = document.getElementById('post-content');
    var scrollTop = document.documentElement.scrollTop
                    || document.body.scrollTop
                    || window.pageYOffset;
    var eles = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");

    if (eles.length == 0) {
        return;
    }

    var idx = -1;
    var biaScrollTop = scrollTop + 50;
    for (var i = 0; i < eles.length; ++i) {
        if (biaScrollTop >= eles[i].offsetTop) {
            idx = i;
        } else {
            break;
        }
    }

    var header = '';
    if (idx != -1) {
        header = eles[idx].id;
    }

    highlightItemOnlyInOutline(header);
});

var highlightItemOnlyInOutline = function(id) {
    var cl = 'outline-bold';
    var outlineContent = document.getElementById('outline-content');
    var eles = outlineContent.querySelectorAll("a");
    var target = null;
    for (var i = 0; i < eles.length; ++i) {
        var ele = eles[i];
        if (ele.getAttribute('data') == id) {
            target = ele;
            ele.classList.add(cl);
        } else {
            ele.classList.remove(cl);
        }
    }

    // TODO: scroll target into view within the outline panel scroll area.
};

</script>


<!-- HEAD_PLACE_HOLDER -->
</head>
<body>
<div class="container-fluid">
<div class="row flex-xl-nowrap">
    <div id="outline-panel" style="display:none;" class="d-none d-md-block d-xl-block col-md-3 col-xl-2 bd-toc">
        <div id="outline-content" class="section-nav"></div>
    </div>
    <div id="post-content" class="col-12 col-md-9 col-xl-10 py-md-3 pl-md-5 bd-content">
    <div style="page-break-after: always;"></div>
<h1 id="toc_0">23. 非对称加密<a class="vnote-anchor" href="#toc_0" data-anchor-icon="#"></a></h1>
<p><img src='' alt="" class="view-image"></p>
<p>  正如我们在处理安全性时所看到的那样，框架提供了在其REST客户端和服务端之间传输的内容的内置加密，尤其是通过自定义编码或HTTPS。后者在使用TLS 1.2和经过验证的模式时，实现了最先进的安全性。但是默认的mORMot加密，即使使用经验证的算法，如AES256-CFB和SHA256，也使用对称密钥，即在客户端和服务器端共享相同的密钥。</p>
<p>  非对称加密，也称为公钥加密，使用成对密钥：</p>
<ul>
<li>可以广泛传播的公钥；</li>
<li>配对的私钥，只有所有者知道。</li>
</ul>
<p>  框架具有完整的非对称加密系统，基于椭圆曲线加密（ECC），可用于应用程序级别（即保护您的应用程序数据），或用于传输级别（以增强通信安全性）。</p>
<h2 id="toc_1">23.1. 公钥加密<a class="vnote-anchor" href="#toc_1" data-anchor-icon="#"></a></h2>
<p>  生成公钥/私钥对后，您可以执行两个功能：</p>
<ul>
<li>验证私钥持有者的消息；应使用证书系统来维持信任链的权威；</li>
<li>使用公钥加密消息以确保只有配对的私钥持有者才能解密它。</li>
</ul>
<h3 id="toc_2">23.1.1. 密钥生成和分发<a class="vnote-anchor" href="#toc_2" data-anchor-icon="#"></a></h3>
<p>  第一个过程是生成一对公钥/私钥。一些随机数生成器（可能基于外部熵源）将收集不可预测的数字，这些数字将由公钥算法使用以生成实际的密钥集。由于所涉及的算法的复杂性以及私钥秘密存储所需的加密，该步骤通常需要一些计算能力。</p>
<p>  让我们解释经典的Alice/Bob方案是如何工作的的：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-1" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 607 292" style="max-width:607px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-1 .node&gt;rect { ; }
#mermaid-diagram-1 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-1 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-1 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-1 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M144.5,64L144.5,89L144.5,114" marker-end="url(#arrowhead16)" style="fill:none"></path><defs><marker id="arrowhead16" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M109.15957446808511,158L69,183L69,208" marker-end="url(#arrowhead17)" style="fill:none"></path><defs><marker id="arrowhead17" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M179.8404255319149,158L220,183L220,208" marker-end="url(#arrowhead18)" style="fill:none"></path><defs><marker id="arrowhead18" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M443.25,64L443.25,89L443.25,114" marker-end="url(#arrowhead19)" style="fill:none"></path><defs><marker id="arrowhead19" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M408.72872340425533,158L369.5,183L369.5,208" marker-end="url(#arrowhead20)" style="fill:none"></path><defs><marker id="arrowhead20" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M477.77127659574467,158L517,183L517,208" marker-end="url(#arrowhead21)" style="fill:none"></path><defs><marker id="arrowhead21" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A1" transform="translate(144.5,42)" style="opacity: 1;"><rect rx="0" ry="0" x="-59" y="-22" width="118" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-49,-12)"><foreignObject width="98" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Random Seed</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(144.5,136)" style="opacity: 1;"><rect rx="0" ry="0" x="-101.5" y="-22" width="203" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-91.5,-12)"><foreignObject width="183" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Key Generation Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(69,230)" style="opacity: 1;"><rect rx="0" ry="0" x="-49" y="-22" width="98" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-39,-12)"><foreignObject width="78" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alice.public</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(220,230)" style="opacity: 1;"><rect rx="0" ry="0" x="-52" y="-22" width="104" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-42,-12)"><foreignObject width="84" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alice.private</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(443.25,42)" style="opacity: 1;"><rect rx="0" ry="0" x="-59" y="-22" width="118" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-49,-12)"><foreignObject width="98" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Random Seed</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(443.25,136)" style="opacity: 1;"><rect rx="0" ry="0" x="-101.5" y="-22" width="203" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-91.5,-12)"><foreignObject width="183" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Key Generation Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(369.5,230)" style="opacity: 1;"><rect rx="0" ry="0" x="-47.5" y="-22" width="95" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-37.5,-12)"><foreignObject width="75" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">bob.public</div></foreignObject></g></g></g><g class="node cyan" id="C4" transform="translate(517,230)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">bob.private</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  现在我们有两对键：</p>
<ul>
<li>Alice的<code>alice.public</code>和<code>alice.private</code>；</li>
<li>Bob的<code>bob.public</code>和<code>bob.private</code>。</li>
</ul>
<p>  根据设计，公钥（<code>alice.public</code>和<code>bob.public</code>）可以通过邮件、应用程序设置、不受保护的文件、甚至公共服务发布。相反，私钥（<code>alice.private</code>或<code>bob.private</code>）则应尽可能保密，并且通常是加密的，然后存储在受密码保护的文件中，操作系统的某个安全位置，甚至专用硬件中。</p>
<p>  在实践中，Alice会将她的<code>alice.public</code>键发送给Bob，以便：</p>
<ul>
<li>Bob可以验证Alice发送的消息的数字签名，Alice用她的<code>alice.private</code>密钥签名;</li>
<li>Bob可以使用已知的<code>alice.public</code>密钥加密某些信息，然后将其发送给Alice，只有Alice可以使用她的<code>alice.private</code>密钥对其进行解密。</li>
</ul>
<p>  当然，由于Bob拥有自己的一对密钥，他也会发布他的<code>bob.public</code>密钥，以便：</p>
<ul>
<li>Alice可以验证Blob发送的消息的数字签名，Blob是用他的<code>bob.private</code>密钥签名的；</li>
<li>Alice可以使用已知的<code>bob.public</code>密钥加密某些信息，然后将其发送给Bob，而且只有Bob可以使用他的<code>bob.private</code>密钥对其进行解密。</li>
</ul>
<p>  密钥分发是任何非对称加密方案的重要组成部分。整个安全链安全程度取决于其最薄弱的环节，因此私钥的保密性需要尽可能多的关注。每个涉及安全性的软件解决方案都可能需要外部审核，至少是同行评审，以验证每个实施。</p>
<h3 id="toc_3">23.1.2. 消息验证<a class="vnote-anchor" href="#toc_3" data-anchor-icon="#"></a></h3>
<p>  可以使用发件人的私钥对各种类型的消息（很可能是文件或内存缓冲区）进行数字签名以支持身份验证。然后，在另一方面，接收方可以使用发送方的公钥来验证消息签名。</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-2" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 954 366" style="max-width:954px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-2 .node&gt;rect { ; }
#mermaid-diagram-2 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-2 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-2 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-2 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph1" transform="translate(194.625,173)" style="opacity: 1;"><rect width="349.25" height="306" x="-174.625" y="-153"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-139" fill="black" stroke="none" id="mermaid-diagram-2Text" style="text-anchor: middle;"> Alice</text></g><g class="cluster" id="subGraph0" transform="translate(631.75,173)" style="opacity: 1;"><rect width="485" height="306" x="-242.5" y="-153"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-139" fill="black" stroke="none" id="mermaid-diagram-2Text" style="text-anchor: middle;"> Bob</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M117.75,89L117.75,114L151.3936170212766,139" marker-end="url(#arrowhead77)" style="fill:none"></path><defs><marker id="arrowhead77" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M271.25,89L271.25,114L223.24468085106383,139" marker-end="url(#arrowhead78)" style="fill:none"></path><defs><marker id="arrowhead78" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M181,183L181,220L181,257" marker-end="url(#arrowhead79)" style="fill:none"></path><defs><marker id="arrowhead79" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M473.25,89L473.25,114L556.2287234042553,139" marker-end="url(#arrowhead80)" style="fill:none"></path><defs><marker id="arrowhead80" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M629.25,89L629.25,114L629.25,139" marker-end="url(#arrowhead81)" style="fill:none"></path><defs><marker id="arrowhead81" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M787.75,89L787.75,114L703.4414893617021,139" marker-end="url(#arrowhead82)" style="fill:none"></path><defs><marker id="arrowhead82" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M575.2754237288135,183L484.5,220L484.5,257" marker-end="url(#arrowhead83)" style="fill:none"></path><defs><marker id="arrowhead83" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M685.7415254237288,183L780.75,220L780.75,257" marker-end="url(#arrowhead84)" style="fill:none"></path><defs><marker id="arrowhead84" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(484.5,220)" style="opacity: 1;"><g transform="translate(-3.5,-12)" class="label"><foreignObject width="7" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(780.75,220)" style="opacity: 1;"><g transform="translate(-3.5,-12)" class="label"><foreignObject width="7" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">?</span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A1" transform="translate(117.75,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-51.5" y="-22" width="103" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.5,-12)"><foreignObject width="83" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.txt</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(271.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-52" y="-22" width="104" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-42,-12)"><foreignObject width="84" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alice.private</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(181,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-74" y="-22" width="148" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64,-12)"><foreignObject width="128" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Signing Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(181,279)" style="opacity: 1;"><rect rx="0" ry="0" x="-57" y="-22" width="114" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-47,-12)"><foreignObject width="94" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.sign</div></foreignObject></g></g></g><g class="node cyan" id="A3" transform="translate(473.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-49" y="-22" width="98" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-39,-12)"><foreignObject width="78" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alive.public</div></foreignObject></g></g></g><g class="node cyan" id="A4" transform="translate(629.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-57" y="-22" width="114" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-47,-12)"><foreignObject width="94" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.sign</div></foreignObject></g></g></g><g class="node cyan" id="A5" transform="translate(787.75,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-51.5" y="-22" width="103" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.5,-12)"><foreignObject width="83" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.txt</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(629.25,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-78.5" y="-22" width="157" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68.5,-12)"><foreignObject width="137" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Verifying Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(484.5,279)" style="opacity: 1;"><rect rx="0" ry="0" x="-42" y="-22" width="84" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-32,-12)"><foreignObject width="64" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">accepted</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(780.75,279)" style="opacity: 1;"><rect rx="0" ry="0" x="-38.5" y="-22" width="77" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-28.5,-12)"><foreignObject width="57" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">rejected</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  如您所见，如果Bob信任来自Alice的alice.public文件，他可以验证messate.txt内容确实是由Alice发送的。大多数情况下，在这种简单的场景中，Alice可能直接将她的<code>alice.public</code>文件提供给Bob，例如通过电子邮件。但是对于大多数复杂的场景，例如可以使用mORMot框架构建的客户端/服务端解决方案，过多的环节会导致密钥潜在的风险。</p>
<h3 id="toc_4">23.1.3. 证书和公钥基础设施<a class="vnote-anchor" href="#toc_4" data-anchor-icon="#"></a></h3>
<p>  使用公钥密码的一个核心问题是确信某个特定公钥是真实的，即该公钥属于声明的个人或实体，且没有被恶意第三方篡改或替换。数字签名不仅仅是创建一些内容的散列，或者对其应用某种“密封”，应该使用托管在公钥基础设施(PKI)中的公钥进行验证。一个或多个第三方，即所谓认证机构(CA)，通过提供一些在线服务、参考公钥的本地安全存储来证明密钥对的所有权，但要对自己的私钥保密。任何证书颁发机构都可以使用自己的私钥对消息进行签名，甚至可以将自己的权限委托给另一个证书实例，方法是使用自己的私钥对中间权限进行签名。如果一个证书被破坏，即如果它的私钥已经被公开，整个信任链就会被破坏，所有依赖的证书都应该立即被撤销。</p>
<p>  实际上，当在这样的可信PKI系统中生成公共证书密钥时，它将包含：</p>
<ul>
<li>真实的公钥资料，视乎所使用的基础算法而定；</li>
<li>一些所有权信息（即谁发出它）；</li>
<li>认证范围（可能适用于用户、公司、网站、应用程序......）；</li>
<li>经过认证的一个或多个其他证书链，使用其私钥进行签名，可使用CA链的已知公钥证明其真实性；</li>
<li>可选的有效期和撤销日期，因此定期续订证书是一种很好的做法。</li>
</ul>
<p>  私钥存储还可以包含添加到其私钥材料的非常相同的信息集。它将强制公钥和私钥之间的一致性，如在关联的公共证书过期后，您不会被使用的私钥所欺骗。</p>
<p>  证书颁发机构创建一个信任链，用作验证公钥的参考。每个操作系统或Internet浏览器都包含一些根证书，整个Internet安全性（HTTPS/TLS）由这样的PKI管理。当然，对于您自己的一组应用程序或产品，您可以创建自己的密钥链，保持相同的原则，主要是私钥保密和信任链管理。</p>
<h3 id="toc_5">23.1.4. 邮件加密<a class="vnote-anchor" href="#toc_5" data-anchor-icon="#"></a></h3>
<p>  隐藏消息内容的一种简单方法是使用密钥，然后将其应用于消息。这样做已经有很长时间了，它的安全性不亚于对称密钥的安全性。为此，你必须相信接收者不会将密钥传播给公众，事实上，你不应该相信任何人，即使是你自己！</p>
<p>  公钥加密通过使用公钥加密消息来解决这个问题，因此只有知道相应私钥的人才能解密。</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-3" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 836.75 342" style="max-width:836.75px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-3 .node&gt;rect { ; }
#mermaid-diagram-3 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-3 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-3 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-3 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph1" transform="translate(220.5,161)" style="opacity: 1;"><rect width="401" height="282" x="-200.5" y="-141"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-127" fill="black" stroke="none" id="mermaid-diagram-3Text" style="text-anchor: middle;"> Alice</text></g><g class="cluster" id="subGraph0" transform="translate(618.875,161)" style="opacity: 1;"><rect width="355.75" height="282" x="-177.875" y="-141"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-127" fill="black" stroke="none" id="mermaid-diagram-3Text" style="text-anchor: middle;"> Bob</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M137,89L137,114L184.87234042553192,139" marker-end="url(#arrowhead136)" style="fill:none"></path><defs><marker id="arrowhead136" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M317,89L317,114L269.1276595744681,139" marker-end="url(#arrowhead137)" style="fill:none"></path><defs><marker id="arrowhead137" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M227,183L227,208L227,233" marker-end="url(#arrowhead138)" style="fill:none"></path><defs><marker id="arrowhead138" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M543,89L543,114L583.0265957446809,139" marker-end="url(#arrowhead139)" style="fill:none"></path><defs><marker id="arrowhead139" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M693.5,89L693.5,114L653.4734042553191,139" marker-end="url(#arrowhead140)" style="fill:none"></path><defs><marker id="arrowhead140" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M618.25,183L618.25,208L618.25,233" marker-end="url(#arrowhead141)" style="fill:none"></path><defs><marker id="arrowhead141" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A1" transform="translate(137,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-78" y="-22" width="156" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68,-12)"><foreignObject width="136" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.encrypted</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(317,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-52" y="-22" width="104" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-42,-12)"><foreignObject width="84" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alice.private</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(227,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-86" y="-22" width="172" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-76,-12)"><foreignObject width="152" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Decryption Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(227,255)" style="opacity: 1;"><rect rx="0" ry="0" x="-51.5" y="-22" width="103" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.5,-12)"><foreignObject width="83" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.txt</div></foreignObject></g></g></g><g class="node cyan" id="A3" transform="translate(543,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-49" y="-22" width="98" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-39,-12)"><foreignObject width="78" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alive.public</div></foreignObject></g></g></g><g class="node cyan" id="A4" transform="translate(693.5,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-51.5" y="-22" width="103" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.5,-12)"><foreignObject width="83" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.txt</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(618.25,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-85" y="-22" width="170" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-75,-12)"><foreignObject width="150" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Encryption Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(618.25,255)" style="opacity: 1;"><rect rx="0" ry="0" x="-78" y="-22" width="156" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68,-12)"><foreignObject width="136" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.encrypted</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  当然，您不仅可以使用另一端公钥加密邮件，还可以对邮件进行签名。 以下是如何实现<code>sign-then-encrypt</code>模式：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-4" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1053.5 554" style="max-width:1053.5px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-4 .node&gt;rect { ; }
#mermaid-diagram-4 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-4 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-4 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-4 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph1" transform="translate(278.375,267)" style="opacity: 1;"><rect width="516.75" height="494" x="-258.375" y="-247"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-233" fill="black" stroke="none" id="mermaid-diagram-4Text" style="text-anchor: middle;"> Alice</text></g><g class="cluster" id="subGraph0" transform="translate(785.125,267)" style="opacity: 1;"><rect width="456.75" height="494" x="-228.375" y="-247"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-233" fill="black" stroke="none" id="mermaid-diagram-4Text" style="text-anchor: middle;"> Bob</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M719.25,89L719.25,114L760.4734042553191,139" marker-end="url(#arrowhead236)" style="fill:none"></path><defs><marker id="arrowhead236" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M901.4893617021277,89L872.5,114L832.2074468085107,139" marker-end="url(#arrowhead237)" style="fill:none"></path><defs><marker id="arrowhead237" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M796.75,183L796.75,208L796.75,233" marker-end="url(#arrowhead238)" style="fill:none"></path><defs><marker id="arrowhead238" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M640.75,277L640.75,302L722.2659574468086,327" marker-end="url(#arrowhead239)" style="fill:none"></path><defs><marker id="arrowhead239" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M796.75,277L796.75,302L795.2872340425532,327" marker-end="url(#arrowhead240)" style="fill:none"></path><defs><marker id="arrowhead240" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M942.563829787234,89L960.25,114L960.25,161L960.25,208L960.25,255L960.25,302L871.8191489361702,327" marker-end="url(#arrowhead241)" style="fill:none"></path><defs><marker id="arrowhead241" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M794,371L794,408L794,445" marker-end="url(#arrowhead242)" style="fill:none"></path><defs><marker id="arrowhead242" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M179.25,89L179.25,114L217.68085106382978,139" marker-end="url(#arrowhead243)" style="fill:none"></path><defs><marker id="arrowhead243" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M380.9308510638298,89L348.75,114L297.02127659574467,139" marker-end="url(#arrowhead244)" style="fill:none"></path><defs><marker id="arrowhead244" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M251.5,183L251.5,208L251.5,233" marker-end="url(#arrowhead245)" style="fill:none"></path><defs><marker id="arrowhead245" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M102.5,277L102.5,302L181.75531914893617,327" marker-end="url(#arrowhead246)" style="fill:none"></path><defs><marker id="arrowhead246" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M251.5,277L251.5,302L251.5,327" marker-end="url(#arrowhead247)" style="fill:none"></path><defs><marker id="arrowhead247" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M434.4095744680851,89L463,114L463,161L463,208L463,255L463,302L330,331.55555555555554" marker-end="url(#arrowhead248)" style="fill:none"></path><defs><marker id="arrowhead248" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M200.6949152542373,371L115.25,408L115.25,445" marker-end="url(#arrowhead249)" style="fill:none"></path><defs><marker id="arrowhead249" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M312.7457627118644,371L415.75,408L415.75,445" marker-end="url(#arrowhead250)" style="fill:none"></path><defs><marker id="arrowhead250" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(115.25,408)" style="opacity: 1;"><g transform="translate(-3.5,-12)" class="label"><foreignObject width="7" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">?</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(415.75,408)" style="opacity: 1;"><g transform="translate(-3.5,-12)" class="label"><foreignObject width="7" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel">?</span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A3" transform="translate(179.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-52" y="-22" width="104" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-42,-12)"><foreignObject width="84" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alice.private</div></foreignObject></g></g></g><g class="node cyan" id="A4" transform="translate(409.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-92.5" y="-22" width="185" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-82.5,-12)"><foreignObject width="165" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.signencrypted</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(251.5,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-86" y="-22" width="172" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-76,-12)"><foreignObject width="152" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Decryption Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(102.5,255)" style="opacity: 1;"><rect rx="0" ry="0" x="-47.5" y="-22" width="95" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-37.5,-12)"><foreignObject width="75" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">bob.public</div></foreignObject></g></g></g><g class="node cyan" id="C4" transform="translate(251.5,255)" style="opacity: 1;"><rect rx="0" ry="0" x="-51.5" y="-22" width="103" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.5,-12)"><foreignObject width="83" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.txt</div></foreignObject></g></g></g><g class="node cyan" id="D2" transform="translate(251.5,349)" style="opacity: 1;"><rect rx="0" ry="0" x="-78.5" y="-22" width="157" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68.5,-12)"><foreignObject width="137" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Verifying Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="E2" transform="translate(115.25,467)" style="opacity: 1;"><rect rx="0" ry="0" x="-42" y="-22" width="84" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-32,-12)"><foreignObject width="64" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">accepted</div></foreignObject></g></g></g><g class="node cyan" id="E3" transform="translate(415.75,467)" style="opacity: 1;"><rect rx="0" ry="0" x="-38.5" y="-22" width="77" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-28.5,-12)"><foreignObject width="57" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">rejected</div></foreignObject></g></g></g><g class="node cyan" id="A1" transform="translate(927,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-51.5" y="-22" width="103" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-41.5,-12)"><foreignObject width="83" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.txt</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(719.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">bob.private</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(796.75,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-74" y="-22" width="148" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64,-12)"><foreignObject width="128" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Signing Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(640.75,255)" style="opacity: 1;"><rect rx="0" ry="0" x="-49" y="-22" width="98" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-39,-12)"><foreignObject width="78" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">alice.public</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(796.75,255)" style="opacity: 1;"><rect rx="0" ry="0" x="-57" y="-22" width="114" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-47,-12)"><foreignObject width="94" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.sign</div></foreignObject></g></g></g><g class="node cyan" id="D1" transform="translate(794,349)" style="opacity: 1;"><rect rx="0" ry="0" x="-85" y="-22" width="170" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-75,-12)"><foreignObject width="150" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Encryption Algorithm</div></foreignObject></g></g></g><g class="node cyan" id="E1" transform="translate(794,467)" style="opacity: 1;"><rect rx="0" ry="0" x="-92.5" y="-22" width="185" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-82.5,-12)"><foreignObject width="165" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">message.signencrypted</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  与往常一样，<code>alice.public</code>和<code>bob.public</code>密钥针对公钥基础设施（PKI）的证书的信任链进行验证。</p>
<p>  有了所有这些元素，我们现在可以将它们应用到我们的mORMot应用程序中。</p>
<h2 id="toc_6">23.2. 椭圆曲线密码学<a class="vnote-anchor" href="#toc_6" data-anchor-icon="#"></a></h2>
<p>  该框架基于“椭圆曲线离散对数问题”的数学结构，实现了椭圆曲线密码体制(ECC)。自从1985年Koblitz和Miller独立提出这个问题以来，数学界在改进算法方面没有取得任何重大进展。简而言之，公钥是椭圆曲线的方程以及曲线上的点，私钥是一个数字。由于椭圆曲线的对称性，ECC公钥值和私钥值之间也存在某种对称性，ECDSA和ECDH算法利用这种对称性来计算数字签名或共享密钥。</p>
<p>  与RSA算法相比，ECC具有以下优点：</p>
<ul>
<li>较小的密钥大小，相同的安全级别（256位椭圆曲线密钥与3072位RSA密钥相当）；</li>
<li>得到大多数认证机构（NIST/NSA）的认可；</li>
<li>更快的性能，特别是当密钥大小增加时；</li>
<li>提供完美的转发保密性，因为每次加密都会创建一个新的密钥；</li>
<li>在所有实际设备中，侵犯专利的可能性要小一些；</li>
<li>最后但同样重要的是，它是Web未来最强大的算法之一。</li>
</ul>
<p>  毫无疑问，我们决定重新实现一个完整的公钥加密堆栈，而不是使用现有的库(如OpenSSL)和已建立的标准(如X509)，这一决定将受到批评。</p>
<p>  公平地说，这些库是复杂和令人困惑的，而我们选择了一套面向未来的算法（AES256，不包括ECB、HMAC-SHA256、PBKDF2_HMAC_SHA256、ECDSA、ECIES…），以遵循mORMot的友好和简洁原则，保持代码的可维护和可读性，减少风险评估的范围。我们遵循所有确定的最佳实践，并试图从一开始就避免缓冲区溢出、弱协议、低熵、低默认值、串行冲突、取证漏洞、隐藏内存副本、恶意优化。我们最不想做的事情就是一开始就使用dll，如果是操作系统的一部分，这些dll可能是弃用、不安全的。最后但同样重要的是，它很有趣，我们学到了很多，我们希望你会喜欢使用它，并作出贡献!</p>
<h3 id="toc_7">23.2.1. SynEcc介绍<a class="vnote-anchor" href="#toc_7" data-anchor-icon="#"></a></h3>
<p>  mORMot的<code>SynEcc.pas</code>单元使用<code>secp256r1</code>曲线（即<code>NIST P-256</code>或OpenSSL的<code>prime256v1</code>）实现完整的ECC计算。底层计算是在优化的C代码中完成的，来自<code>https://github.com/esxgx/easy-ecc</code>开源项目，并且在Windows或Linux可执行文件中静态链接：即没有必需的外部<code>.dll</code>/<code>.so</code>库。在我们没有提供静态<code>.o</code>文件的目标（如BSD、MacOSX或ARM）系统上，有一个优化的pascal版本可用。然后，我们在这个坚实的ECC基础上定义了一组功能丰富的object pascal类，包括证书、私钥的安全存储、公钥的JSON发布，作为集成工具集。</p>
<p>  所有需要的底层非对称加密技术都可用：</p>
<ul>
<li>ECC密钥生成，使用<code>SynCrypto.pas</code>的安全<code>TAESPRNG</code>作为随机种子；</li>
<li>256位哈希的ECDSA签名和验证;</li>
<li>ECDSH共享秘密计算，适合ECIES加密，经过PBKDF2_HMAC_SHA256推导。</li>
</ul>
<p>  同一个<code>SynEcc.pas</code>单元定义了一些高级类和结构，用于实现：</p>
<ul>
<li>授权证书，通过公共<code>TECCCertificate</code>和私有<code>TECCCertificateSecret</code>类，以及完整的PKI证书链，参见<code>TECCCertificateChain</code>；</li>
<li>文件或内存缓冲区的数字签名，通过<code>TECCSignatureCertified</code>；</li>
<li>加密文件或内存缓冲区，调用<code>TECCCertificate.Encrypt</code>和<code>TECCCertificateSecret.Decrypt</code>方法；</li>
<li>创新的<code>.cheat</code>文件生成，用于安全存储私钥密码，使用<code>cheat.public</code>密钥及密码加密。</li>
</ul>
<p>  当需要一些高级加密时，您可以在您的程序中自由地使用这些类，相信我，情况最终就是这样的！为了方便对文件的操作，还开发了命令行ECC工具。</p>
<h3 id="toc_8">23.2.2. ECC命令行工具<a class="vnote-anchor" href="#toc_8" data-anchor-icon="#"></a></h3>
<p>  您将在<code>SQLite3\Samples\33 - ECC</code>文件夹中找到<code>ECC.dpr</code>控制台项目的源代码。 只需将其编译为可执行文件，即可从命令行提示符访问。 或者从<code>http://synopse.info/files/ecc.7z</code>下载已编译的版本</p>
<p>  它在Windows或Linux下没有任何问题，没有外部依赖（如不需要OpenSSL），因此可以在自动化服务器基础结构中使用。 无需部署复杂的PKI系统，只需通过一个命令行工具管理您的证书、加密和签名等详细信息。</p>
<p>  如果你在没有参数的情况下运行它，你将获得简单的帮助信息（这里是撰写本文时的列表，你自己的版本可能会有所不同）：</p>
<pre><code class="hljs">&gt;ecc

Synopse ECC certificate-based public-key cryptography
-----------------------------------------------------
Using mORMot's SynECC rev. 1.18.3112

ECC help
ECC new -auth key.private -authpass authP@ssW0rd -authrounds 60000
      -issuer toto@toto.com -start 2016-10-30 -days 30
      -newpass P@ssw0RD@ -newrounds 60000
ECC rekey -auth key.private -authpass P@ssW0rd -authrounds 60000
      -newpass newP@ssw0RD@ -newrounds 60000
ECC sign -file some.doc -auth key.private -pass P@ssW0rd -rounds 60000
ECC verify -file some.doc -auth key.public
ECC source -auth key.private -pass P@ssW0rd -rounds 60000
      -const MY_PRIVKEY -comment "My Private Key"
ECC infopriv -auth key.private -pass P@ssW0rd -rounds 60000
ECC chain file1.public file2.public file3.public ...
ECC chainall
ECC crypt -file some.doc -out some.doc.synecc -auth key.public
      -saltpass salt -saltrounds 60000
ECC decrypt -file some.doc.synecc -out some.doc -auth key.private
      -authpass P@ssW0rd -authrounds 60000 -saltpass salt -saltrounds 60000
ECC infocrypt -file some.doc.synecc
ECC cheatinit -newpass MasterP@ssw0RD@ -newrounds 100000
ECC cheat -auth key.private -authpass MasterP@ssw0RD@ -authrounds 100000

Note that you can add the -noprompt switch for no console interactivity.
</code></pre>
<p>  如您所见，该操作首先定义关键字（<code>new sign verify source...</code>），然后可以提供一些以<code>-key value</code>键值对形式的可选参数。 如果未指定参数，ECC控制台应用程序将提示输入，具有用户友好的提示和足够的默认值。</p>
<p>  您可以定义<code>-noprompt</code>开关以完全不强制执行控制台交互，以支持从其他进程或批处理文件自动使用。 <code>ECCProcess.pas</code>单元发布ECC工具的所有高级命令，因此可以在您自己的设置或维护项目中重用。</p>
<p>  我们现在将使用此<code>ECC</code>工具显示<code>SynEcc</code>单元的最常见功能，并显示与每个操作对应的代码。</p>
<h3 id="toc_9">23.2.3. 密钥和证书生成<a class="vnote-anchor" href="#toc_9" data-anchor-icon="#"></a></h3>
<p>  第一步是创建一个新的密钥对，它将包含自己的认证信息：</p>
<pre><code class="hljs">&gt;ecc new
Enter the first chars of the .private file name of the signing authority.
Will create a self-signed certificate if left void.
Auth:

Enter Issuer identifier text.
Will be truncated to 15-20 ascii-7 chars.
Issuer [arbou] :

Enter the YYYY-MM-DD start date of its validity.
0 will create a never-expiring certificate
Start [2016-09-23] :

Enter the number of days of its validity.
Days [365] :

Enter a private PassPhrase for the new key (at least 8 chars long).
Save this in a safe place: if you forget it, the key will be useless!
NewPass [#weLHn5E.Qfe] :

Enter the PassPhrase iteration round for the new key (at least 1000).
The higher, the safer, but will demand more computation time.
NewRounds [60000] :

Corresponding TSynPersistentWithPassword.ComputePassword:
 encryption ErHdwwro/8jFsCZC
 authMutual 5qMgx6Miv+O71+VYL95zk6U2wP79lKL3s1BFnd+a
 authServer 5qMhx6Miv+O71+VYL95zk6U2wP79lKL3s1BFnd+a
 authClient 5qMix6Miv+O71+VYL95zk6U2wP79lKL3s1BFnd+a

 8BC90201EF55EE34F62DBA8FE8CF14DC.public/.private file created.
</code></pre>
<p>  这里我们使用默认值，包括生成的安全密码（<code>#weLHn5E.Qfe</code>）。您应该在安全的地方记下此密码，因为任何私钥的使用都需要这个密码，如签名或解密邮件时。如果您忘记了此密码，将无法再访问此私钥。</p>
<p>  我们将在下面看到如何启用<code>ECC cheat</code>模式以使用<code>cheat.public</code>密钥将生成的<code>.private</code>密钥密码存储在<code>.cheat</code>加密本地文件中，以便使用 <code>cheat.private</code>密钥及其密码安全地恢复密码。</p>
<p>  最后一行包含生成的密钥的标识符（或序号），此十六进制值（<code>8BC90201EF55EE34F62DBA8FE8CF14DC</code>）将用于在外部标识密钥，并在内部（包括其他证书）用于映射此特定密钥。请注意，您不需要在<code>ECC</code>工具中键入序号的所有字符，只要第一个字符足够（如<code>8BC9</code>），只要它们能识别当前文件夹中的一个唯一文件即可。</p>
<p>  您可以检查当前文件夹中生成的文件：</p>
<pre><code class="hljs">&gt;dir *.p*
23/09/2016  13:46             2 320 8BC90201EF55EE34F62DBA8FE8CF14DC.private
23/09/2016  13:46               544 8BC90201EF55EE34F62DBA8FE8CF14DC.public
</code></pre>
<p>  <code>.private</code>是一些原始二进制内容，使用<code>#weLHn5E.Qfe</code>密码加密。</p>
<p>  相反，<code>.public</code>文件存储为普通的JSON对象：</p>
<pre><code class="lang-json hljs">{
 <span class="hljs-attr">"Version"</span>: <span class="hljs-number">1</span>,
 <span class="hljs-attr">"Serial"</span>: <span class="hljs-string">"8BC90201EF55EE34F62DBA8FE8CF14DC"</span>,
 <span class="hljs-attr">"Issuer"</span>: <span class="hljs-string">"arbou"</span>,
 <span class="hljs-attr">"IssueDate"</span>: <span class="hljs-string">"2016-09-23"</span>,
 <span class="hljs-attr">"ValidityStart"</span>: <span class="hljs-string">"2016-09-23"</span>,
 <span class="hljs-attr">"ValidityEnd"</span>: <span class="hljs-string">"2017-09-23"</span>,
 <span class="hljs-attr">"AuthoritySerial"</span>: <span class="hljs-string">"8BC90201EF55EE34F62DBA8FE8CF14DC"</span>,
 <span class="hljs-attr">"AuthorityIssuer"</span>: <span class="hljs-string">"arbou"</span>,
 <span class="hljs-attr">"IsSelfSigned"</span>: <span class="hljs-literal">true</span>,
 <span class="hljs-attr">"Base64"</span>: <span class="hljs-string">"AQA1ADUAogGLyQIB71XuNPYtuo/ozxTcGrODgAAAAAAAAAAAAAAAAIvJAgHvVe409i26j+jPFNwas4OAAA
AAAAAAAAAAAAAAAqjxQhWz5NjFLoWBsqvWyywne8ncNVSi/MmnVg+IZ4WknxoNvAia6oBBhC/tpo3zTjUQDssB8AId+/QR
SF15RccuOy/j/ebeqX6qxANtZEZO3dT/sWBUjQy/CYIVQe5TSDZy5pQAAAAA"</span>
}
</code></pre>
<p>  您可以查看存储在<code>TECCCertificate</code>实例中的所有信息。<code>"Base64"</code>字段实际上是整个内容的原始序列化，因此其字符串值包含公共证书的所有信息，如应用程序设置。</p>
<p>  我们没有在第一个<code>Auth:</code>提示符处指定任何权限。 因此，此密钥对将是自签名证书，请参阅上述JSON中的<code>"IsSelfSigned": true</code>字段，并且<code>"Serial"</code>和 <code>"AuthoritySerial"</code>标识符匹配。 我们将它用作根证书来创建证书链。</p>
<p>  所有其他证书最终将由此根证书授权签名，例如：</p>
<pre><code class="hljs">&gt;ecc new
Enter the first chars of the .private file name of the signing authority.
Will create a self-signed certificate if left void.
Auth: 8

Will use: 8BC90201EF55EE34F62DBA8FE8CF14DC.private

Enter the PassPhrase of this .private file.
AuthPass: #weLHn5E.Qfe

Enter the PassPhrase iteration rounds of this .private file.
AuthRounds [60000] :

Enter Issuer identifier text.
Will be truncated to 15-20 ascii-7 chars.
Issuer [arbou] : toto

Enter the YYYY-MM-DD start date of its validity.
0 will create a never-expiring certificate.
Start [2016-09-23] : 0

Enter a private PassPhrase for the new key (at least 8 chars long).
Save this in a safe place: if you forget it, the key will be useless!
NewPass [b3dEB+DW8BJd] :

Corresponding TSynPersistentWithPassword.ComputePassword:
 cIK5hkjDu5/98mwm

Enter the PassPhrase iteration round for the new key (at least 1000).
The higher, the safer, but will demand more computation time.
NewRounds [60000] :

 03B8865C6B982A39E9EFB1DC1A95D227.public/.private file created.
</code></pre>
<p>  如您所见，我们仅为第一个<code>Auth:</code>提示输入了<code>8</code>，并且该工具在当前文件夹中找到一个<code>8*.private</code>文件。 然后我们输入了相关的<code>#weLHn5E.Qfe</code>密码，任何错误的密码都会中断密钥生成。 此权限将永远不会过期（我们为<code>Start:</code>提示符输入<code>0</code>），但由于其根证书具有过期日期，因此它将在根过期时到期。</p>
<p>  现在我们可以看到两组键：</p>
<pre><code class="hljs">&gt;dir *.p*
23/09/2016  14:27             2 320 03B8865C6B982A39E9EFB1DC1A95D227.private
23/09/2016  14:27               524 03B8865C6B982A39E9EFB1DC1A95D227.public
23/09/2016  13:46             2 320 8BC90201EF55EE34F62DBA8FE8CF14DC.private
23/09/2016  13:46               544 8BC90201EF55EE34F62DBA8FE8CF14DC.public
</code></pre>
<p>  新创建的<code>.public</code>文件包含：</p>
<pre><code class="lang-json hljs">{
 <span class="hljs-attr">"Version"</span>: <span class="hljs-number">1</span>,
 <span class="hljs-attr">"Serial"</span>: <span class="hljs-string">"03B8865C6B982A39E9EFB1DC1A95D227"</span>,
 <span class="hljs-attr">"Issuer"</span>: <span class="hljs-string">"toto"</span>,
 <span class="hljs-attr">"IssueDate"</span>: <span class="hljs-string">"2016-09-23"</span>,
 <span class="hljs-attr">"ValidityStart"</span>: <span class="hljs-string">""</span>,
 <span class="hljs-attr">"ValidityEnd"</span>: <span class="hljs-string">""</span>,
 <span class="hljs-attr">"AuthoritySerial"</span>: <span class="hljs-string">"8BC90201EF55EE34F62DBA8FE8CF14DC"</span>,
 <span class="hljs-attr">"AuthorityIssuer"</span>: <span class="hljs-string">"arbou"</span>,
 <span class="hljs-attr">"IsSelfSigned"</span>: <span class="hljs-literal">false</span>,
 <span class="hljs-attr">"Base64"</span>: <span class="hljs-string">"AQA1AAAAAAADuIZca5gqOenvsdwaldInhiGAAAAAAAAAAAAAAAAAAIvJAgHvVe409i26j+jPFNwas4OAAAA
AAAAAAAAAAAAAA2rPT7XPmCH6xIt3+710FFYVAPBPWhcsR6uwYoyndrqNI7557iYC7qLrfKPgp6EmEENX4Vw0tEexu3O9SJ
OAG/EHau0BtwoqZBNhJEiUyGqKa0ioMwasbKtjJBNMfX7EMIsnxn4AAAAA"</span>
}
</code></pre>
<p>  您可以看到<code>"Serial"</code>、<code>"AuthoritySerial"</code>和<code>"IsSelfSigned"</code>字段的预期值。</p>
<p>  我们可以运行以下命令在当前文件夹中创建一个包含所有可用密钥的证书链：</p>
<pre><code class="hljs">&gt;ecc chainall
 chain.ca file created.
</code></pre>
<p>  <code>chain.ca</code>文件是一个JSON对象，包含整个证书链的所有公共信息，<code>"PublicBase64"</code>JSON数组可以复制粘贴到您的应用程序设置或源代码中，然后通过<code>TECCCertificateChain</code>类使用：</p>
<pre><code class="lang-json hljs">{
 <span class="hljs-attr">"PublicBase64"</span>:
 [
  <span class="hljs-string">"AQA1AAAAAA..."</span>,
  <span class="hljs-string">"AQA1ADUAogG..."</span>
 ],
 <span class="hljs-attr">"Items"</span>:
 [
  {
   <span class="hljs-attr">"Version"</span>: <span class="hljs-number">1</span>,
   <span class="hljs-attr">"Serial"</span>: <span class="hljs-string">"03B8865C6B982A39E9EFB1DC1A95D227"</span>,
   <span class="hljs-attr">"Issuer"</span>: <span class="hljs-string">"toto"</span>,
   <span class="hljs-attr">"IssueDate"</span>: <span class="hljs-string">"2016-09-23"</span>,
   <span class="hljs-attr">"ValidityStart"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"ValidityEnd"</span>: <span class="hljs-string">""</span>,
   <span class="hljs-attr">"AuthoritySerial"</span>: <span class="hljs-string">"8BC90201EF55EE34F62DBA8FE8CF14DC"</span>,
   <span class="hljs-attr">"AuthorityIssuer"</span>: <span class="hljs-string">"arbou"</span>,
   <span class="hljs-attr">"IsSelfSigned"</span>: <span class="hljs-literal">false</span>
  },
  {
   <span class="hljs-attr">"Version"</span>: <span class="hljs-number">1</span>,
   <span class="hljs-attr">"Serial"</span>: <span class="hljs-string">"8BC90201EF55EE34F62DBA8FE8CF14DC"</span>,
   <span class="hljs-attr">"Issuer"</span>: <span class="hljs-string">"arbou"</span>,
   <span class="hljs-attr">"IssueDate"</span>: <span class="hljs-string">"2016-09-23"</span>,
   <span class="hljs-attr">"ValidityStart"</span>: <span class="hljs-string">"2016-09-23"</span>,
   <span class="hljs-attr">"ValidityEnd"</span>: <span class="hljs-string">"2017-09-23"</span>,
   <span class="hljs-attr">"AuthoritySerial"</span>: <span class="hljs-string">"8BC90201EF55EE34F62DBA8FE8CF14DC"</span>,
   <span class="hljs-attr">"AuthorityIssuer"</span>: <span class="hljs-string">"arbou"</span>,
   <span class="hljs-attr">"IsSelfSigned"</span>: <span class="hljs-literal">true</span>
  }
 ],
 <span class="hljs-attr">"Count"</span>: <span class="hljs-number">2</span>,
}
</code></pre>
<p>  在上面的示例中，我们缩减了<code>"PublicBase64"</code>值，以节省笔墨。它们映射<code>.public</code> JSON文件中已有的内容。实际上，相同的信息被存储两次：一次在<code>"PublicBase64"</code>中，另一次存储在<code>"Items"</code>项的每个单独的属性（<code>"Version", "Serial", "Issuer"...</code>）中。</p>
<p>  密钥管理的一种简单方法是保证存储空间的安全（如一对USB笔式驱动器，其中至少一个保存在物理库中），然后将所有证书链放在专用文件夹中。所有公钥，即<code>*.public</code>和<code>chain.ca</code>文件，都是公开的，所以可以随处发布。只需关注<code>.private</code>文件及其相关密码即可。硬件安全的驱动器可能是一种过度安全，因为<code>.private</code>文件已经过加密和密码保护，拥有最先进的软件保护，即<code>AFSplit</code>反取证扩散和针对<code>PBKDF2_HMAC_SHA256</code>派生密码的<code>AES256-CFB</code>加密，使用了大量的迭代（60000）。</p>
<p>  请记住，安全链中最薄弱的环节通常是在椅子和键盘之间，而不是在计算机内。不要在密钥之间重复使用密码，并记住<code>ECC</code>工具有<code>"rekey"</code>命令，这样您就可以更改私钥密码，而无需更改其内容，也无需重新发布其关联的<code>.public</code>密钥：</p>
<pre><code class="hljs">&gt;ecc rekey
Enter the first chars of the .private certificate file name.
Auth: 8

Will use: 8BC90201EF55EE34F62DBA8FE8CF14DC.private

Enter the PassPhrase of this .private file.
AuthPass: #weLHn5E.Qfe

Enter the PassPhrase iteration rounds of this .private file.
AuthRounds [60000] :

Enter a NEW private PassPhrase for the key (at least 8 chars long).
Save this in a safe place: if you forget it, the key will be useless!
NewPass [mPy3kjWHE@LK] :

Corresponding TSynPersistentWithPassword.ComputePassword:
 f+Gk8GGCqICA8GoJ

Enter the NEW PassPhrase iteration round for the key (at least 1000).
The higher, the safer, but will demand more computation time.
NewRounds [60000] :

 8BC90201EF55EE34F62DBA8FE8CF14DC.private file created.
</code></pre>
<p>  从现在开始，根证书将期望<code>mPy3kjWHE@LK</code>作为关键短语，用于访问其<code>.private</code>内容。 例如（使用包括<code>-noprompt</code>选项的命令行开关），您现在可以编写：</p>
<pre><code class="hljs">&gt;ecc infopriv -auth 8B -pass mPy3kjWHE@LK -noprompt
{
        "Version": 1,
        "Serial": "8BC90201EF55EE34F62DBA8FE8CF14DC",
        "Issuer": "arbou",
        "IssueDate": "2016-09-23",
        "ValidityStart": "2016-09-23",
        "ValidityEnd": "2017-09-23",
        "AuthoritySerial": "8BC90201EF55EE34F62DBA8FE8CF14DC",
        "AuthorityIssuer": "arbou",
        "IsSelfSigned": true,
        "Base64": "AQA1ADUAogG...."
}
</code></pre>
<p>  这里，<code>"Base64":</code>字段仅包含公钥信息，而不包含私钥内容，私钥内容保密，从不作为JSON序列化。</p>
<h3 id="toc_10">23.2.4. TECCCertificate和TECCCertificateSecret<a class="vnote-anchor" href="#toc_10" data-anchor-icon="#"></a></h3>
<p>  作为参考，以下是使用<code>TECCCertificateSecret</code>类在<code>ECC</code>工具中实现创建新证书、生成<code>.private</code>/<code>.public</code>文件的方法：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ECCCommandNew</span><span class="hljs-params">(<span class="hljs-keyword">const</span> AuthPrivKey: TFileName;
  <span class="hljs-keyword">const</span> AuthPassword: RawUTF8; AuthPasswordRounds: integer;
  <span class="hljs-keyword">const</span> Issuer: RawUTF8; StartDate: TDateTime; ExpirationDays: integer;
  <span class="hljs-keyword">const</span> SavePassword: RawUTF8; SavePassordRounds, SplitFiles: integer)</span>:</span> TFileName;
<span class="hljs-keyword">var</span> auth,new: TECCCertificateSecret;
<span class="hljs-keyword">begin</span>
  <span class="hljs-keyword">if</span> AuthPrivKey=<span class="hljs-string">''</span> <span class="hljs-keyword">then</span>
    auth := <span class="hljs-keyword">nil</span> <span class="hljs-keyword">else</span>
    auth := TECCCertificateSecret.CreateFromSecureFile(AuthPrivKey,AuthPassword,AuthPasswordRounds);
  <span class="hljs-keyword">try</span>
    <span class="hljs-comment">// generate pair</span>
    new := TECCCertificateSecret.CreateNew(auth,Issuer,ExpirationDays,StartDate);
    <span class="hljs-keyword">try</span>
      <span class="hljs-comment">// save private key as .private password-protected binary file</span>
      new.SaveToSecureFiles(SavePassword,<span class="hljs-string">'.'</span>,SplitFiles,<span class="hljs-number">64</span>,SavePassordRounds);
      <span class="hljs-comment">// save public key as .public JSON file</span>
      result := ChangeFileExt(new.SaveToSecureFileName,ECCCERTIFICATEPUBLIC_FILEEXT);
      ObjectToJSONFile(new,result);
    <span class="hljs-keyword">finally</span>
      new.Free;
    <span class="hljs-keyword">end</span>;
  <span class="hljs-keyword">finally</span>
    auth.Free;
  <span class="hljs-keyword">end</span>;
<span class="hljs-keyword">end</span>;
</code></pre>
<p>  请参阅<code>SynEcc.pas</code>单元API参考，尤其是<code>TECCCertificateChain</code>和<code>TECCCertificateChainFile</code>类，它们允许使用以下构造函数将证书链存储为JSON文件或基于64位编码字符串的JSON数组：</p>
<pre><code class="lang-pascal hljs">    <span class="hljs-function"><span class="hljs-keyword">constructor</span> <span class="hljs-title">CreateFromJson</span><span class="hljs-params">(<span class="hljs-keyword">const</span> json: RawUTF8)</span>;</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span> <span class="hljs-title">CreateFromArray</span><span class="hljs-params">(<span class="hljs-keyword">const</span> values: TRawUTF8DynArray)</span>;</span>
</code></pre>
<p>  您可以使用<code>ECC</code>工具的<code>"source"</code>命令生成一些pascal常量源代码，其中包含一个加密的私钥，可以嵌入到您的可执行文件中。 例如：</p>
<pre><code class="hljs">&gt;ecc source -auth 8 -pass mPy3kjWHE@LK -const MY_PRIV -noprompt
Will use: 8BC90201EF55EE34F62DBA8FE8CF14DC.private

 8BC90201EF55EE34F62DBA8FE8CF14DC.private.inc file created.
</code></pre>
<p>  您可以查看生成的<code>.private.inc</code>文件，通过复制和粘贴直接在源代码中使用它：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">const</span>
  MY_PRIV: <span class="hljs-keyword">array</span>[<span class="hljs-number">0</span>..<span class="hljs-number">255</span>] <span class="hljs-keyword">of</span> byte = (
    $C3,$<span class="hljs-number">31</span>,$<span class="hljs-number">17</span>,$<span class="hljs-number">48</span>,$<span class="hljs-number">35</span>,$B6,$<span class="hljs-number">30</span>,$AA,$<span class="hljs-number">87</span>,$ED,$AE,$DF,$<span class="hljs-number">84</span>,$<span class="hljs-number">29</span>,$AA,$<span class="hljs-number">85</span>,
    $<span class="hljs-number">8</span>D,$BF,$A0,$<span class="hljs-number">05</span>,$<span class="hljs-number">92</span>,$<span class="hljs-number">7</span>F,$<span class="hljs-number">6</span>C,$<span class="hljs-number">47</span>,$<span class="hljs-number">66</span>,$D7,$<span class="hljs-number">23</span>,$B3,$<span class="hljs-number">5</span>B,$<span class="hljs-number">4</span>C,$<span class="hljs-number">42</span>,$<span class="hljs-number">97</span>,
    $<span class="hljs-number">5</span>B,$<span class="hljs-number">07</span>,$<span class="hljs-number">73</span>,$<span class="hljs-number">3</span>B,$FE,$FA,$BE,$A7,$<span class="hljs-number">96</span>,$<span class="hljs-number">9</span>B,$F9,$<span class="hljs-number">1</span>D,$<span class="hljs-number">84</span>,$CC,$<span class="hljs-number">6</span>E,$F0,
    $C9,$A1,$A7,$<span class="hljs-number">2</span>A,$<span class="hljs-number">24</span>,$<span class="hljs-number">8</span>D,$<span class="hljs-number">4</span>A,$B3,$F3,$B3,$<span class="hljs-number">89</span>,$<span class="hljs-number">52</span>,$<span class="hljs-number">70</span>,$<span class="hljs-number">46</span>,$<span class="hljs-number">83</span>,$<span class="hljs-number">84</span>,
    $<span class="hljs-number">5</span>D,$FD,$E7,$E9,$C3,$D9,$DC,$<span class="hljs-number">07</span>,$C1,$FF,$<span class="hljs-number">82</span>,$F8,$<span class="hljs-number">78</span>,$<span class="hljs-number">45</span>,$BF,$<span class="hljs-number">18</span>,
    $CA,$F7,$EE,$<span class="hljs-number">8</span>E,$A3,$<span class="hljs-number">42</span>,$<span class="hljs-number">0</span>D,$<span class="hljs-number">0</span>B,$<span class="hljs-number">35</span>,$<span class="hljs-number">2</span>F,$<span class="hljs-number">20</span>,$<span class="hljs-number">4</span>A,$<span class="hljs-number">65</span>,$<span class="hljs-number">82</span>,$<span class="hljs-number">4</span>A,$<span class="hljs-number">78</span>,
    $C4,$<span class="hljs-number">41</span>,$<span class="hljs-number">19</span>,$<span class="hljs-number">0</span>E,$<span class="hljs-number">98</span>,$<span class="hljs-number">77</span>,$<span class="hljs-number">7</span>D,$<span class="hljs-number">81</span>,$<span class="hljs-number">58</span>,$DB,$<span class="hljs-number">04</span>,$C9,$<span class="hljs-number">52</span>,$<span class="hljs-number">2</span>E,$<span class="hljs-number">5</span>F,$<span class="hljs-number">07</span>,
    $CF,$<span class="hljs-number">44</span>,$<span class="hljs-number">34</span>,$<span class="hljs-number">93</span>,$<span class="hljs-number">1</span>B,$FD,$<span class="hljs-number">00</span>,$<span class="hljs-number">38</span>,$E0,$E7,$DC,$<span class="hljs-number">3</span>A,$AC,$CB,$<span class="hljs-number">14</span>,$<span class="hljs-number">73</span>,
    $B2,$E0,$<span class="hljs-number">13</span>,$BE,$<span class="hljs-number">84</span>,$<span class="hljs-number">79</span>,$F7,$<span class="hljs-number">55</span>,$<span class="hljs-number">8</span>A,$<span class="hljs-number">12</span>,$<span class="hljs-number">4</span>F,$<span class="hljs-number">9</span>A,$<span class="hljs-number">09</span>,$<span class="hljs-number">97</span>,$CC,$<span class="hljs-number">9</span>B,
    $<span class="hljs-number">8</span>E,$<span class="hljs-number">7</span>C,$<span class="hljs-number">04</span>,$<span class="hljs-number">92</span>,$<span class="hljs-number">93</span>,$<span class="hljs-number">24</span>,$<span class="hljs-number">73</span>,$<span class="hljs-number">50</span>,$<span class="hljs-number">41</span>,$B3,$<span class="hljs-number">92</span>,$<span class="hljs-number">54</span>,$D7,$<span class="hljs-number">66</span>,$<span class="hljs-number">05</span>,$<span class="hljs-number">4</span>A,
    $<span class="hljs-number">3</span>E,$<span class="hljs-number">4</span>F,$D4,$<span class="hljs-number">1</span>B,$<span class="hljs-number">94</span>,$<span class="hljs-number">71</span>,$AA,$<span class="hljs-number">04</span>,$<span class="hljs-number">29</span>,$<span class="hljs-number">42</span>,$B3,$<span class="hljs-number">57</span>,$B0,$F3,$<span class="hljs-number">24</span>,$<span class="hljs-number">74</span>,
    $<span class="hljs-number">19</span>,$<span class="hljs-number">8</span>E,$BA,$<span class="hljs-number">52</span>,$FA,$D6,$<span class="hljs-number">56</span>,$<span class="hljs-number">99</span>,$<span class="hljs-number">7</span>B,$<span class="hljs-number">73</span>,$<span class="hljs-number">1</span>B,$D0,$<span class="hljs-number">8</span>B,$<span class="hljs-number">3</span>A,$<span class="hljs-number">95</span>,$AB,
    $<span class="hljs-number">94</span>,$<span class="hljs-number">63</span>,$C2,$C0,$<span class="hljs-number">78</span>,$<span class="hljs-number">05</span>,$<span class="hljs-number">9</span>C,$<span class="hljs-number">8</span>B,$<span class="hljs-number">85</span>,$B7,$A1,$E3,$ED,$<span class="hljs-number">93</span>,$<span class="hljs-number">27</span>,$<span class="hljs-number">18</span>,
    $F6,$DD,$<span class="hljs-number">87</span>,$D7,$E9,$<span class="hljs-number">35</span>,$<span class="hljs-number">74</span>,$<span class="hljs-number">01</span>,$<span class="hljs-number">2</span>E,$<span class="hljs-number">35</span>,$DF,$<span class="hljs-number">1</span>A,$<span class="hljs-number">6</span>E,$FA,$<span class="hljs-number">4</span>A,$<span class="hljs-number">3</span>F,
    $E3,$<span class="hljs-number">70</span>,$<span class="hljs-number">19</span>,$A3,$D7,$E3,$<span class="hljs-number">39</span>,$<span class="hljs-number">37</span>,$<span class="hljs-number">59</span>,$<span class="hljs-number">15</span>,$<span class="hljs-number">43</span>,$B2,$F4,$<span class="hljs-number">36</span>,$B5,$<span class="hljs-number">64</span>,
    $D6,$BF,$<span class="hljs-number">75</span>,$<span class="hljs-number">12</span>,$<span class="hljs-number">6</span>B,$C5,$<span class="hljs-number">89</span>,$<span class="hljs-number">95</span>,$<span class="hljs-number">2</span>D,$E5,$<span class="hljs-number">70</span>,$<span class="hljs-number">64</span>,$EB,$<span class="hljs-number">70</span>,$<span class="hljs-number">98</span>,$<span class="hljs-number">9</span>D);
  MY_PRIV_LEN = SizeOf(MY_PRIV);
  MY_PRIV_ROUNDS = <span class="hljs-number">100</span>;
  MY_PRIV_SERIAL = <span class="hljs-string">'8BC90201EF55EE34F62DBA8FE8CF14DC'</span>;
  MY_PRIV_PASS = <span class="hljs-string">'Oute?/I#JSxL0VcLeR/HY(yr'</span>;
  MY_PRIV_CYPH = <span class="hljs-string">'2R3VSFXfikiNaKTM3MqbTlw+PiMBwshk'</span>;
</code></pre>
<p>  通过这些类，您可以拥有在客户端/服务器应用程序中实现自己的私有和安全PKI逻辑所需的一切。</p>
<h3 id="toc_11">23.2.5. 文件签名<a class="vnote-anchor" href="#toc_11" data-anchor-icon="#"></a></h3>
<p>  从这两个文本文件开始：</p>
<pre><code class="hljs">&gt;dir test*.*
19/09/2016  21:46            94 161 test1.txt
05/09/2016  10:37            72 209 test2.txt
</code></pre>
<p>  为了签署<code>test1.txt</code>，按照<a href="">非对称数字签名</a>中提到的，我们将运行以下命令：</p>
<pre><code class="hljs">&gt;ecc sign -file test1.txt
Enter the first chars of the .private file name of the signing authority.
Auth: 8B

Will use: 8BC90201EF55EE34F62DBA8FE8CF14DC.private

Enter the PassPhrase of this .private file.
Pass: mPy3kjWHE@LK

Enter the PassPhrase iteration rounds of this .private file.
Rounds [60000] :

 test1.txt.sign file created.
</code></pre>
<p>  如您所见，出现了一个新的<code>.sign</code>文件：</p>
<pre><code class="hljs">&gt;dir test*.*
19/09/2016  21:46            94 161 test1.txt
24/09/2016  16:24               369 test1.txt.sign
05/09/2016  10:37            72 209 test2.txt
</code></pre>
<p>  它是一个简单的JSON对象，包含有关<code>test1.txt</code>文件的一些信息：</p>
<pre><code class="lang-json hljs">{
        <span class="hljs-attr">"meta"</span>: {
                <span class="hljs-attr">"name"</span>: <span class="hljs-string">"test1.txt"</span>,
                <span class="hljs-attr">"date"</span>: <span class="hljs-string">"2016-09-19T21:46:24"</span>
        },
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">94161</span>,
        <span class="hljs-attr">"md5"</span>: <span class="hljs-string">"e80f2bf959c943e240f2c1f5efcf1e89"</span>,
        <span class="hljs-attr">"sha256"</span>: <span class="hljs-string">"6bc2d25e9cc93201914e7c6588624696778de80c6f63a590262ccf610310ea0e"</span>,
        <span class="hljs-attr">"sign"</span>: <span class="hljs-string">"AQA2AIvJAgHvVe409i26j+jPFNwas4OAAAAAAAAAA...."</span>
}
</code></pre>
<p>  除了一些常规信息（名称，日期，大小）之外，还有无符号散列（<code>"md5"</code>和<code>"sha256"</code>）和<code>ECC</code>数字签名，在<code>"sign":</code>字段中存储为base-64编码字符串。 此签名是使用<code>8BC90201EF55EE34F62DBA8FE8CF14DC.private</code>密钥和<code>test1.txt</code>文件内容的SHA256哈希计算的。 请注意，只要不修改<code>size/md5/sha256/sign</code>值，就可以向任何<code>.sign</code>文件添加所需的任何JSON字段，尤其是在<code>"meta":</code>嵌套对象中。</p>
<p>  要验证该文件，请确保<code>test1.txt</code>和<code>test1.txt.sign</code>文件都在当前目录中，然后运行：</p>
<pre><code class="hljs">&gt;ecc verify -file test1.txt
 test1.txt file verified as valid self signed.
</code></pre>
<p>  由于<code>8BC90201EF55EE34F62DBA8FE8CF14DC.private</code>密钥使用自身权限进行签名，因此报告为<code>"valid self signed"</code>。 使用另一个机构颁发的证书验证的签名将返回<code>"valid signed"</code>。</p>
<p>  现在，如果您修改<code>test1.txt</code>，如更改一个字符，验证将失败：</p>
<pre><code class="hljs">&gt;ecc verify -file test1.txt
 test1.txt file verification failure: invalid signature (9).
</code></pre>
<p>  不要忘记修复<code>test1.txt</code>内容，因为我们现在将它用作加密源。</p>
<p>  要检查您是否还原为原始文件内容，请运行：</p>
<pre><code class="hljs">&gt;ecc verify -file test1.txt
 test1.txt file verified as valid self signed.
</code></pre>
<h3 id="toc_12">23.2.6. 使用代码签名<a class="vnote-anchor" href="#toc_12" data-anchor-icon="#"></a></h3>
<p>  从源代码的角度来看，您可以使用<code>TECCCertificateSecret.SignFile</code>方法在项目中轻松添加非对称数字签名，或者通过<code>TECCCertificateSecret.SignToBase64</code>重载方法使用内存缓冲区而不是文件。</p>
<p>  作为参考，以下是在<code>ECC</code>工具中实现签名的方式：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ECCCommandSignFile</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FileToSign, AuthPrivKey: TFileName;
  <span class="hljs-keyword">const</span> AuthPassword: RawUTF8; AuthPasswordRounds: integer)</span>:</span> TFileName;
<span class="hljs-keyword">var</span> auth: TECCCertificateSecret;
<span class="hljs-keyword">begin</span>
  auth := TECCCertificateSecret.CreateFromSecureFile(AuthPrivKey,AuthPassword,AuthPasswordRounds);
  <span class="hljs-keyword">try</span>
    result := auth.SignFile(FileToSign,[]);
  <span class="hljs-keyword">finally</span>
    auth.Free;
  <span class="hljs-keyword">end</span>;
<span class="hljs-keyword">end</span>;
</code></pre>
<p>  验证可以通过专用的<code>TECCSignatureCertified</code>类完成：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ECCCommandVerifyFile</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FileToVerify, AuthPubKey: TFileName;
  <span class="hljs-keyword">const</span> AuthBase64: RawUTF8)</span>:</span> TECCValidity;
<span class="hljs-keyword">var</span> content: RawByteString;
    auth: TECCCertificate;
    cert: TECCSignatureCertified;
<span class="hljs-keyword">begin</span>
  content := StringFromFile(FileToVerify);
  <span class="hljs-keyword">if</span> content=<span class="hljs-string">''</span> <span class="hljs-keyword">then</span>
    <span class="hljs-keyword">raise</span> EECCException.CreateUTF8(<span class="hljs-string">'File not found: %'</span>,[FileToVerify]);
  cert := TECCSignatureCertified.CreateFromFile(FileToVerify);
  <span class="hljs-keyword">try</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> cert.Check <span class="hljs-keyword">then</span> <span class="hljs-keyword">begin</span>
      result := ecvInvalidSignature;
      <span class="hljs-keyword">exit</span>;
    <span class="hljs-keyword">end</span>;
    auth := TECCCertificate.Create;
    <span class="hljs-keyword">try</span>
      <span class="hljs-keyword">if</span> auth.FromAuth(AuthPubKey,AuthBase64,cert.AuthoritySerial) <span class="hljs-keyword">then</span>
        result := cert.Verify(auth,pointer(content),length(content)) <span class="hljs-keyword">else</span>
        result := ecvUnknownAuthority;
    <span class="hljs-keyword">finally</span>
      auth.Free;
    <span class="hljs-keyword">end</span>;
  <span class="hljs-keyword">finally</span>
    cert.Free;
  <span class="hljs-keyword">end</span>;
<span class="hljs-keyword">end</span>;
</code></pre>
<p>  这里，签名授权作为单个<code>.public</code>本地文件提供，加载到<code>TECCCertificate</code>实例中，但您的项目可以使用<code>TECCCertificateChain</code>作为完整的PKI权限链。</p>
<h3 id="toc_13">23.2.7. 文件加密<a class="vnote-anchor" href="#toc_13" data-anchor-icon="#"></a></h3>
<p>  为了加密两个测试文件，如<a href="">非对称加密方案</a>中所提出的，我们将运行以下命令：</p>
<pre><code class="hljs">&gt;ecc crypt -file test1.txt -auth 03 -saltpass monsecret -noprompt
Will use: 03B8865C6B982A39E9EFB1DC1A95D227.public

 test1.txt.synecc file created.

&gt;ecc crypt -file test2.txt -auth 03 -saltpass monsecret2 -noprompt
Will use: 03B8865C6B982A39E9EFB1DC1A95D227.public

 test2.txt.synecc file created.
</code></pre>
<p>  我们可以看到，已经计算了两个新的<code>.synecc</code>加密文件：</p>
<pre><code class="hljs">&gt;dir test*
24/09/2016  16:36            94 161 test1.txt
24/09/2016  16:24               369 test1.txt.sign
24/09/2016  17:13            22 436 test1.txt.synecc
05/09/2016  10:37            72 209 test2.txt
24/09/2016  17:13            15 220 test2.txt.synecc
</code></pre>
<p>  您可能会注意到<code>.synecc</code>文件小于原始<code>.txt</code>文件...实际上，<code>SynEcc</code>确实认为普通内容很容易压缩，在加密步骤之前对其应用了<code>SynLZ</code>压缩。</p>
<p>  如果我们要求提供有关<code>test1.txt.synecc</code>文件的信息：</p>
<pre><code class="hljs">&gt;ecc infocrypt -file test1.txt.synecc
{
        "Date": "2016-09-24",
        "Size": 94161,
        "Recipient": "toto",
        "RecipientSerial": "03B8865C6B982A39E9EFB1DC1A95D227",
        "FileTime": "2016-09-24T16:36:59",
        "Algorithm": "ecaPBKDF2_HMAC_SHA256_AES256_CFB_SYNLZ",
        "RandomPublicKey": "038C73D421D9A7F2F7FFC0F3EF62C79897D13064EF2D6FAA0DB0F246CD9B173B90",
        "HMAC": "c6bf56792e58c68c45ebdff1fbd6a3b2e4d3e95e522f41eba2ecab41fd53183b",
        "Signature": {
                "Version": 1,
                "Date": "2016-09-24",
                "AuthoritySerial": "8BC90201EF55EE34F62DBA8FE8CF14DC",
                "AuthorityIssuer": "arbou",
                "ECDA": "2AwyyNYAcfSyJW+5BzvksbSdXcOUbYNqm...."
        }
}
</code></pre>
<p>  我们可以看到存储在文件头中的信息，包括收件人名称和<code>.publickey</code>标识符，以及<code>"PBKDF2_HMAC_SHA256_AES256_CFB_SYNLZ"</code>算法，它确实包括<code>_SYNLZ</code>压缩。 也可用其他算法（具有不同的AES链接模式），并且将来可能会添加一些新方法。</p>
<p>  <code>ecc crypt</code>命令也包含了当前文件夹中<code>test1.txt</code>可用的数字签名的签名文件，实际上遵循<a href="">非对称的先签名后加密方案</a>，而<code>test2.txt.synecc</code>没有任何嵌入式签名，因为没有可用的<code>test2.txt.sign</code>签名文件：</p>
<pre><code class="hljs">&gt;ecc infocrypt -file test2.txt.synecc
{
        "Date": "2016-09-24",
        "Size": 72209,
        "Recipient": "toto",
        "RecipientSerial": "03B8865C6B982A39E9EFB1DC1A95D227",
        "FileTime": "2016-09-05T10:37:50",
        "Algorithm": "ecaPBKDF2_HMAC_SHA256_AES256_CFB_SYNLZ",
        "RandomPublicKey": "03914AA67BCC92F78A9D670B2209587E3C97A3E08FD39A38B459558511F88F7651",
        "HMAC": "07ddc90f7695fff8ca0683be98f7b1043e13a7bceb79f0d6a929069c5d9767d1",
        "Signature": null
}
</code></pre>
<p>  如您所见，加密由其<code>"Algorithm":</code>字段定义，并使用两个附加属性：</p>
<ul>
<li><code>"RandomPublicKey"</code>包含由<code>ecc crypt</code>生成的真正密钥，允许完美的前向保密，这意味着为每次加密计算共享密钥：如果有人实现了破坏用于加密特定<code>.synecc</code>文件的AES256-CFB密钥（如花费大量资金的暴力搜索），此密钥将不能重复用于任何其他文件：上面的每个<code>"RandomPublicKey"</code>值对于每个.<code>synecc</code>文件确实是唯一的；</li>
<li><code>"HMAC":</code>使用安全的消息认证方式，称为密钥哈希消息认证码（HMAC），比它所基于的哈希算法更强，即在我们的例子中是SHA256。</li>
</ul>
<p>  在实践中，<code>SynEcc</code>使用<code>PBKDF2_HMAC_SHA256</code>作为密钥推导函数，<code>AES256-CFB</code>作为对称加密方案，以及用于消息认证的<code>HMAC-SHA256</code>算法，实现了最先进的椭圆曲线集成加密方案（ECIES）。</p>
<p>  请参阅<code>https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme</code></p>
<p>  对于选择明文和选择密文攻击的对手，ECIES提供了语义安全。除了<code>"RandomPublicKey"</code>和<code>"HMAC"</code>属性中预期的真正密钥和消息身份验证之外，<code>SynEcc</code>实现还允许自定义默认的<code>"salt"</code>值，以便为每个<code>.synecc</code>加密文件添加密码保护。</p>
<p>  解密非常简单：</p>
<pre><code class="hljs">&gt;ecc decrypt -file test1.txt.synecc
Enter the name of the decrypted file
Out [test1.txt.2] :

Enter the PassPhrase of the associated .private file.
AuthPass: b3dEB+DW8BJd

Enter the PassPhrase iteration rounds of this .private file.
AuthRounds [60000] :

Enter the optional PassPhrase to be used for decryption.
SaltPass [salt] : monsecret

Enter the PassPhrase iteration rounds.
SaltRounds [60000] :

 test1.txt.2 file verified as valid self signed.
 test1.txt.synecc file decrypted with signature.
 test1.txt.2 file created.
</code></pre>
<p>  对第二个文件进行单步非控制台交互解密：</p>
<pre><code class="hljs">&gt;ecc decrypt -file test2.txt.synecc -authpass b3dEB+DW8BJd -saltpass monsecret2 -noprompt
 test2.txt.synecc file decrypted.
 test2.txt.2 file created.
</code></pre>
<p>  正如预期的那样，第二个文件不包含任何数字签名，因此没有<code>"test2.txt.2 file verified as valid self signed."</code>信息。</p>
<p>  解密的文件在当前文件夹中可用：</p>
<pre><code class="hljs">&gt; dir test*
24/09/2016  16:36            94 161 test1.txt
24/09/2016  16:36            94 161 test1.txt.2
24/09/2016  16:24               369 test1.txt.sign
24/09/2016  17:13            22 436 test1.txt.synecc
05/09/2016  10:37            72 209 test2.txt
05/09/2016  10:37            72 209 test2.txt.2
24/09/2016  17:13            15 220 test2.txt.synecc
</code></pre>
<p>  解压后，<code>*.2</code>解密文件具有预期大小（和内容），甚至文件时间戳也已设置为与原始文件相匹配。</p>
<h3 id="toc_14">23.2.8. 私钥密码作弊模式<a class="vnote-anchor" href="#toc_14" data-anchor-icon="#"></a></h3>
<p>  为了遵循最佳实践，我们的<code>.private</code>密钥文件始终受密码保护。当生成密钥对时，ECC工具总是提供具有足够长度和熵的随机值，并且可以直接使用。始终优先信任计算机以创建真正的随机性（并且<code>SynCrypto.pas</code>的安全<code>TAESPRNG</code>被设计为使用硬件熵，如果可用的话，是最好的种子），而不是使用我们的人脑，这可能会被基于字典的密码攻击击破。由于使用了60,000轮的<code>PBKDF2_HMAC_SHA256</code>基于密码的密钥派生函数，因此暴力破解几乎是不可能的，因此彩虹表（即预先计算的密码列表）将不起作用，并且每个密码尝试将花费比常规密钥更多的时间推导函数。</p>
<p>  强密码的问题在于难以记住。如果您使用的不是纯随机密码，而是一些更容易记住具有良好熵的值，您可以尝试一些工具，如<code>https://xkpasswd.net/s</code>，它返回如<code>$$19*wrong*DRIVE*read*61$$</code>的值。但即使这样，你也只能记住十几个这样的密码。在典型的公钥基础结构中，您可以创建几百个密钥，因此记住所有密码对于普通人来说都不是您和我的选择。</p>
<p>  最后，您将使用一个工具来存储所有密码（最新的一个趋势是使用与浏览器集成的在线服务)，或者，将它们存储在受密码保护的Excel文档中。大多数IT人员，甚至是安全专家，最终都会使用这种存储方式，因为他们需要它。</p>
<p>  可列出此类解决方案的弱点：</p>
<ul>
<li>我们怎么能相信闭源软件和第三方在线服务？</li>
<li>甚至像<code>http://keepass.info/help/base/security.html</code>这样开源的也可能显得很弱（没有PBKDF，没有AFSplit，托管C＃，SHA作为PRNG）；</li>
<li>存储安全依赖于“主密码”安全；</li>
<li>如果“主密码”被泄露，则会曝光所有密码；</li>
<li>您需要知道主密码才能将新项目添加到存储中。</li>
</ul>
<p> &amp;emsp<code>;ECC</code>工具能够以<code>"cheat mode"</code>工作，将所有<code>.private</code>密钥文件生成的密码存储在关联的<code>.cheat</code>本地文件中，使用<code>cheat.public</code>密钥加密。结果是：</p>
<ul>
<li>每个密钥对都有自己的关联<code>.cheat</code>文件，因此您一次只能释放一个密钥；</li>
<li>没有<code>cheat.private</code>密钥和主密码，<code>.cheat</code>文件内容毫无意义，因此您可以将它们与<code>.private</code>文件一起管理和存储；</li>
<li>创建密钥对时只需要<code>cheat.public</code>密钥，因此您不会泄漏主密码，甚至可以在远程服务器上以自动方式生成密钥；</li>
<li><code>cheat.private</code>密钥将安全地存储在一个单独的位置，只有在需要恢复密码时才需要；</li>
<li>它使用强大的文件加密，具有经过验证的PBKDF、AFSplit、AES-PRNG和ECDH / ECIES算法。</li>
</ul>
<p>  默认情况下，不会创建<code>.cheat</code>文件。您需要通过创建<code>cheat.public</code>和<code>cheat.private</code>密钥文件来显式初始化<code>"cheat mode"</code>：</p>
<pre><code class="hljs"> &gt;ecc cheatinit
Enter Issuer identifier text of the master cheat keys.
Will be truncated to 15-20 ascii-7 chars.
Issuer [arbou] :

Enter a private PassPhrase for the master cheat.private key (at least 8 chars).
Save this in a safe place: if you forget it, the key will be useless!
NewPass [uQHH*am39LLj] : verysafelongpassword

Enter iteration rounds for the mastercheat.private key (at least 100000).
NewRounds [100000] :

 cheat.public/.private file created.
</code></pre>
<p>  如您所见，PBKDF默认的迭代次数很高（100000），并且已创建本地文件：</p>
<pre><code class="hljs">&gt;dir cheat.*

18/10/2016  11:12             4 368 cheat.private
18/10/2016  11:12               568 cheat.public
</code></pre>
<p>  现在我们将创建一个新的密钥对（在单个命令行中，没有控制台交互）：</p>
<pre><code class="hljs">&gt;ecc new -newpass NewKeyP@ssw0rd -noprompt

Corresponding TSynPersistentWithPassword.ComputePassword:
 encryption HeOyjDUAsOhvLZkMA0Y=
 authMutual lO0mv+8VpoFrrFfbBFilNppn1WumaIL+AN3JXEUUpCY=
 authServer lO0nv+8VpoFrrFfbBFilNppn1WumaIL+AN3JXEUUpCY=
 authClient lO0kv+8VpoFrrFfbBFilNppn1WumaIL+AN3JXEUUpCY=

 D1045FCBAA1382EE44ED2C212596E9E1.public/.private file created.
</code></pre>
<p>  已创建关联的.cheat文件：</p>
<pre><code class="hljs">&gt;dir D10*

18/10/2016  11:15             1 668 D1045FCBAA1382EE44ED2C212596E9E1.cheat
18/10/2016  11:15             2 320 D1045FCBAA1382EE44ED2C212596E9E1.private
18/10/2016  11:15               588 D1045FCBAA1382EE44ED2C212596E9E1.public
</code></pre>
<p>  想象一下，你忘记了<code>NewKeyP@ssw0rd</code>值，您可以使用以下命令来检索它：</p>
<pre><code class="hljs">&gt;ecc cheat

Enter the first chars of the .private certificate file name.
Auth: D10

Will use: D1045FCBAA1382EE44ED2C212596E9E1.private

Enter the PassPhrase of the master cheat.private file.
AuthPass: verysafelongpassword

Enter the PassPhrase iteration rounds of the cheat.private file.
AuthRounds [100000] :

{
        "pass": "NewKeyP@ssw0rd",
        "rounds": 60000
}
Corresponding TSynPersistentWithPassword.ComputePassword:
 encryption HeOyjDUAsOhvLZkMA0Y=
 authMutual lO0mv+8VpoFrrFfbBFilNppn1WumaIL+AN3JXEUUpCY=
 authServer lO0nv+8VpoFrrFfbBFilNppn1WumaIL+AN3JXEUUpCY=
 authClient lO0kv+8VpoFrrFfbBFilNppn1WumaIL+AN3JXEUUpCY=
</code></pre>
<p>  如果您的<code>.private</code>密钥没有关联的<code>.cheat</code>文件，您将无法恢复密码：</p>
<pre><code class="hljs">&gt;ecc cheat

Enter the first chars of the .private certificate file name.
Auth: 8BC9

Will use: 8BC90201EF55EE34F62DBA8FE8CF14DC.private

Enter the PassPhrase of the master cheat.private file.
AuthPass: verysafelongpassword

Enter the PassPhrase iteration rounds of the cheat.private file.
AuthRounds [100000] :

Fatal exception EECCException raised with message:
 Unknown file 8BC90201EF55EE34F62DBA8FE8CF14DC.cheat
</code></pre>
<p>  实际上，这种<code>"cheat mode"</code>将帮助您实现任何规模的安全公钥基础结构。 它将与主cheat.private密钥文件一样安全，并且其相关密码保持隐藏，当然也只能明智地传播。 不要忘记定期使用<code>ecc rekey</code>命令，以便更改<code>cheat.private</code>的主密码。 此实现的主要好处是，对于所有密钥生成过程，只需要<code>cheat.public</code>密钥文件。</p>
<h3 id="toc_15">23.2.9. 使用代码加密<a class="vnote-anchor" href="#toc_15" data-anchor-icon="#"></a></h3>
<p>  从源代码的角度来看，由于<code>TECCCertificate.Encrypt</code>和<code>TECCCertificateSecret.Decrypt</code>方法，您可以使用<code>TECCCertificate.EncryptFile</code>和<code>TECCCertificateSecret.DecryptFile</code>方法在项目中轻松添加非对称加密，甚至可以用于内存缓冲区。</p>
<p>  ECC工具中如何实现加密，参考如下：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-function"><span class="hljs-keyword">procedure</span> <span class="hljs-title">ECCCommandCryptFile</span><span class="hljs-params">(<span class="hljs-keyword">const</span> FileToCrypt, DestFile, AuthPubKey: TFileName;
  <span class="hljs-keyword">const</span> AuthBase64, AuthSerial, Password: RawUTF8; PasswordRounds: integer; Algo: TECIESAlgo)</span>;</span>
<span class="hljs-keyword">var</span> content: RawByteString;
    auth: TECCCertificate;
<span class="hljs-keyword">begin</span>
  content := StringFromFile(FileToCrypt);
  <span class="hljs-keyword">if</span> content=<span class="hljs-string">''</span> <span class="hljs-keyword">then</span>
    <span class="hljs-keyword">raise</span> EECCException.CreateUTF8(<span class="hljs-string">'File not found: %'</span>,[FileToCrypt]);
  auth := TECCCertificate.Create;
  <span class="hljs-keyword">try</span>
    <span class="hljs-keyword">if</span> auth.FromAuth(AuthPubKey,AuthBase64,AuthSerial) <span class="hljs-keyword">then</span> <span class="hljs-keyword">begin</span>
      auth.EncryptFile(FileToCrypt,DestFile,Password,PasswordRounds,Algo,true);
    <span class="hljs-keyword">end</span>;
  <span class="hljs-keyword">finally</span>
    auth.Free;
    FillZero(content);
  <span class="hljs-keyword">end</span>;
<span class="hljs-keyword">end</span>;
</code></pre>
<p>  在这里，您可能注意到在函数的<code>finally</code>块中使用了<code>FillZero()</code>，这是一种常用且强烈鼓励的方法，可以在使用后保护敏感数据不会留在RAM中。 <code>SynCrypto.pas</code>和<code>SynEcc.pas</code>已经按照类似的安全模式进行了检查，并且没有在程序栈或堆中留下任何敏感信息。</p>
<h2 id="toc_16">23.3. 应用程序锁定<a class="vnote-anchor" href="#toc_16" data-anchor-icon="#"></a></h2>
<p>  专业软件的常见功能要求是防止滥用发布的应用程序。 出于许可或安全原因，可能会要求您“锁定”程序（可能是工具或服务）的执行。</p>
<p>  mORMot可以使用非对称加密技术来确保只允许用户在特定计算机上运行某些可执行文件（可选择使用专用设置）。 该框架提供了第一块砖，您可以在您的专用系统上构建。</p>
<p>  <code>dddInfraApps.pas</code>单元发布以下<code>ECCAuthorize</code>函数和类型：</p>
<pre><code class="lang-pascal hljs"><span class="hljs-keyword">type</span>
  TECCAuthorize = (eaSuccess, eaInvalidSecret, eaMissingUnlockFile,
    eaInvalidUnlockFile, eaInvalidJson);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ECCAuthorize</span><span class="hljs-params">(aContent: TObject; aSecretDays: integer; <span class="hljs-keyword">const</span> aSecretPass,
  aDPAPI, aDecryptSalt, aAppLockPublic64: RawUTF8; <span class="hljs-keyword">const</span> aSearchFolder: TFileName = <span class="hljs-string">''</span>;
  aSecretInfo: PECCCertificateSigned = <span class="hljs-keyword">nil</span>; aLocalFile: PFileName = <span class="hljs-keyword">nil</span>)</span>:</span> TECCAuthorize;
</code></pre>
<p>  此函数将使用多个非对称密钥集：</p>
<ul>
<li>一个主密钥集，如<code>applock.public</code>和<code>applock.private</code>，为系统的所有用户共享；</li>
<li>几个用户特定的密钥集，如<code>user@host.public</code>和<code>user@host.secret</code>，每个用户一个并关联计算机主机名。</li>
</ul>
<p>  执行ECCAuthorize函数时，它将搜索以当前登录用户和计算机主机名命名的本地user@host.unlock文件。当然，第一次为该用户启动应用程序时，将不会有这样的文件。它将创建两个本地user@host.public和user@host.secret文件并返回eaMissingUnlockFile。</p>
<p>  主密钥集将用于数字签名解锁文件：</p>
<ul>
<li><code>applock.public</code>将作为普通的base64编码的<code>aAppLockPublic64</code>文本参数提供在可执行文件中，为了安全起见，您应该确保其值不被攻击者用伪造替换：可执行文件应该被签名，或者至少应该是常量值并在程序执行期间使用CRC检查其内容；</li>
<li>相反，<code>applock.private</code>需要保密，带有相关的密码。</li>
</ul>
<p>  用户专用密钥集将用于加密解锁文件：</p>
<ul>
<li><code>user@host.secret</code>文件实际上包含一个真正的私钥，使用<code>CryptDataForCurrentUser</code>（即Windows下的<code>DPAPI</code>）为特定计算机和用户加密：这将避免<code>user@host.unlock</code>在另一台计算机上重用，即使用户名和主机名相同，并复制了<code>user@host.secret</code>文件。此文件应保留在本地，不需要传输。</li>
<li><code>user@host.public</code>文件将发送给产品支持团队，例如通过电子邮件，如果需要，您也可以设置自动化服务器。支持团队将创建一个与此<code>user@host.public</code>密钥匹配的<code>user@host.unlock</code>，它将解锁给定用户的应用程序。</li>
</ul>
<p>  在支持团队方面，为给定用户创建了一个<code>user@host.json</code>文件，该文件将包含<code>ECCAuthorize</code>函数的<code>aContent: TObject</code>参数的JSON序列化。该对象可以包含任何发布属性，与该用户的安全期望相匹配，如可用的功能或资源访问。</p>
<h3 id="toc_17">23.3.1. 从用户角度来看<a class="vnote-anchor" href="#toc_17" data-anchor-icon="#"></a></h3>
<p>  因此产生的过程如下：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-5" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1248 580" style="max-width:1248px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-5 .node&gt;rect { ; }
#mermaid-diagram-5 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-5 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-5 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-5 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph1" transform="translate(321,280)" style="opacity: 1;"><rect width="602" height="520" x="-301" y="-260"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-246" fill="black" stroke="none" id="mermaid-diagram-5Text" style="text-anchor: middle;"> PC1 Computer</text></g><g class="cluster" id="subGraph0" transform="translate(925,327)" style="opacity: 1;"><rect width="566" height="188" x="-283" y="-94"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-80" fill="black" stroke="none" id="mermaid-diagram-5Text" style="text-anchor: middle;"> Support Team</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M231.25,82.23500810372772L127,114L127,139" marker-end="url(#arrowhead335)" style="fill:none"></path><defs><marker id="arrowhead335" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M331.25,77.09667024704619L514,114L514,139" marker-end="url(#arrowhead336)" style="fill:none"></path><defs><marker id="arrowhead336" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M259.1329787234043,89L234,114L234,161L234,208L234,233L234,280L234,327L234,374L234,421L234,446L238.92021276595744,471" marker-end="url(#arrowhead337)" style="fill:none"></path><defs><marker id="arrowhead337" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M304.0691489361702,89L330,114L330,139" marker-end="url(#arrowhead338)" style="fill:none"></path><defs><marker id="arrowhead338" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M740.5,302L740.5,327L841,353.99142857142857" marker-end="url(#arrowhead339)" style="fill:none"></path><defs><marker id="arrowhead339" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M915.5,302L915.5,327L915.5,352" marker-end="url(#arrowhead340)" style="fill:none"></path><defs><marker id="arrowhead340" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1100,302L1100,327L990,355.02168021680217" marker-end="url(#arrowhead341)" style="fill:none"></path><defs><marker id="arrowhead341" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M915.5,396L915.5,421L428,446L317.75,474.0473612990528" marker-end="url(#arrowhead342)" style="fill:none"></path><defs><marker id="arrowhead342" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M514,183L514,208L514,233L1027,274.14505119453923" marker-end="url(#arrowhead343)" style="fill:none"></path><defs><marker id="arrowhead343" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(281.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Application</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(127,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-72" y="-22" width="144" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62,-12)"><foreignObject width="124" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.secret</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(514,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="B3" transform="translate(243.25,493)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.unlock</div></foreignObject></g></g></g><g class="node cyan" id="B4" transform="translate(330,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-61" y="-22" width="122" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51,-12)"><foreignObject width="102" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.public</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(740.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-63.5" y="-22" width="127" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-53.5,-12)"><foreignObject width="107" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.private</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(915.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-61.5" y="-22" width="123" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51.5,-12)"><foreignObject width="103" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ser1@pc1.json</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(1100,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="D" transform="translate(915.5,374)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.unlock</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  简而言之，每个用户/计算机组合都将拥有自己的一组公共/秘密/解锁文件。</p>
<ul>
<li>在实践中，<code>applock.public</code>可以在应用程序代码中硬编码为普通的base64编码的<code>aAppLockPublic64</code>常量字符串，当然，可执行文件应该使用适当的权限进行签名，以确保此常量不会被伪值替换；</li>
<li>这些本地<code>user@host.*</code>文件的位置默认为可执行文件夹，但可以通过<code>aSearchFolder</code>参数指定，特别是如果此文件夹是只读的（如Windows UAC），或者您使用某些自定义GUI为用户交互；</li>
<li><code>user@host.json</code>将使用<code>applock.private</code>密钥进行签名，以证明生成的<code>user@host.unlock</code>文件确实是由支持团队提供的;</li>
<li><code>user@host.json</code>将使用通过电子邮件收到的<code>user@host.public</code>密钥进行加密，因此将特定于单个用户/计算机组合。</li>
</ul>
<p>  如果两个用户在同一台​​计算机上共享该应用程序，则会出现另一组文件：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-6" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 2239 580" style="max-width:2239px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-6 .node&gt;rect { ; }
#mermaid-diagram-6 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-6 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-6 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-6 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph2" transform="translate(321,280)" style="opacity: 1;"><rect width="602" height="520" x="-301" y="-260"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-246" fill="black" stroke="none" id="mermaid-diagram-6Text" style="text-anchor: middle;"> PC1 Computer</text></g><g class="cluster" id="subGraph1" transform="translate(1898,280)" style="opacity: 1;"><rect width="602" height="520" x="-301" y="-260"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-246" fill="black" stroke="none" id="mermaid-diagram-6Text" style="text-anchor: middle;"> PC2 Computer</text></g><g class="cluster" id="subGraph0" transform="translate(1109.5,327)" style="opacity: 1;"><rect width="935" height="188" x="-467.5" y="-94"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-80" fill="black" stroke="none" id="mermaid-diagram-6Text" style="text-anchor: middle;"> Support Team</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M237.25,81.66458658346333L127,114L127,139" marker-end="url(#arrowhead475)" style="fill:none"></path><defs><marker id="arrowhead475" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M262.3244680851064,89L234,114L234,161L234,208L234,233L234,280L234,327L234,374L234,421L234,446L238.92021276595744,471" marker-end="url(#arrowhead476)" style="fill:none"></path><defs><marker id="arrowhead476" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M312.8776595744681,89L342,114L342,139" marker-end="url(#arrowhead477)" style="fill:none"></path><defs><marker id="arrowhead477" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M337.25,76.84293193717278L526,114L526,139" marker-end="url(#arrowhead478)" style="fill:none"></path><defs><marker id="arrowhead478" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1909.5,76.19765166340508L1704,114L1704,139" marker-end="url(#arrowhead479)" style="fill:none"></path><defs><marker id="arrowhead479" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1931.1808510638298,89L1899,114L1899,139" marker-end="url(#arrowhead480)" style="fill:none"></path><defs><marker id="arrowhead480" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1981.7340425531916,89L2007,114L2007,161L2007,208L2007,233L2007,280L2007,327L2007,374L2007,421L2007,446L2005.1382978723404,471" marker-end="url(#arrowhead481)" style="fill:none"></path><defs><marker id="arrowhead481" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M2009.5,83.37630662020906L2103,114L2103,139" marker-end="url(#arrowhead482)" style="fill:none"></path><defs><marker id="arrowhead482" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M738.5,302L738.5,327L848.5,355.02168021680217" marker-end="url(#arrowhead483)" style="fill:none"></path><defs><marker id="arrowhead483" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M923,302L923,327L923,352" marker-end="url(#arrowhead484)" style="fill:none"></path><defs><marker id="arrowhead484" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1070.531914893617,302L1026.25,327L971.3297872340426,352" marker-end="url(#arrowhead485)" style="fill:none"></path><defs><marker id="arrowhead485" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1145.776595744681,302L1187,327L1238.8617021276596,352" marker-end="url(#arrowhead486)" style="fill:none"></path><defs><marker id="arrowhead486" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1284.5,302L1284.5,327L1284.5,352" marker-end="url(#arrowhead487)" style="fill:none"></path><defs><marker id="arrowhead487" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1469,302L1469,327L1359,355.02168021680217" marker-end="url(#arrowhead488)" style="fill:none"></path><defs><marker id="arrowhead488" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M342,183L342,208L342,233L677,272.70996216897856" marker-end="url(#arrowhead489)" style="fill:none"></path><defs><marker id="arrowhead489" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1899,183L1899,208L1899,233L1542,272.02093023255816" marker-end="url(#arrowhead490)" style="fill:none"></path><defs><marker id="arrowhead490" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M923,396L923,421L428,446L317.75,474.0473612990528" marker-end="url(#arrowhead491)" style="fill:none"></path><defs><marker id="arrowhead491" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1284.5,396L1284.5,421L1802,446L1929,475.6228287841191" marker-end="url(#arrowhead492)" style="fill:none"></path><defs><marker id="arrowhead492" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A1" transform="translate(287.25,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Application</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(127,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-72" y="-22" width="144" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62,-12)"><foreignObject width="124" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.secret</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(243.25,493)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.unlock</div></foreignObject></g></g></g><g class="node cyan" id="B3" transform="translate(342,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="B4" transform="translate(526,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-61" y="-22" width="122" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51,-12)"><foreignObject width="102" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.public</div></foreignObject></g></g></g><g class="node cyan" id="A2" transform="translate(1959.5,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Application</div></foreignObject></g></g></g><g class="node cyan" id="B5" transform="translate(1704,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-72" y="-22" width="144" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62,-12)"><foreignObject width="124" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc2.secret</div></foreignObject></g></g></g><g class="node cyan" id="B6" transform="translate(1899,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc2.public</div></foreignObject></g></g></g><g class="node cyan" id="B7" transform="translate(2003.5,493)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc2.unlock</div></foreignObject></g></g></g><g class="node cyan" id="B8" transform="translate(2103,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-61" y="-22" width="122" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51,-12)"><foreignObject width="102" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.public</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(738.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-61.5" y="-22" width="123" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51.5,-12)"><foreignObject width="103" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ser1@pc1.json</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(923,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(1109.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-63.5" y="-22" width="127" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-53.5,-12)"><foreignObject width="107" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.private</div></foreignObject></g></g></g><g class="node cyan" id="C4" transform="translate(1284.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-61.5" y="-22" width="123" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51.5,-12)"><foreignObject width="103" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">ser2@pc2.json</div></foreignObject></g></g></g><g class="node cyan" id="C5" transform="translate(1469,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user3@pc2.public</div></foreignObject></g></g></g><g class="node cyan" id="D1" transform="translate(923,374)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.unlock</div></foreignObject></g></g></g><g class="node cyan" id="D2" transform="translate(1284.5,374)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc2.unlock</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  几个用户在同一台计算机上将如下处理：</p>
<div class="mermaid-diagram"><svg id="mermaid-diagram-7" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 2144.5 580" style="max-width:2144.5px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaid-diagram-7 .node&gt;rect { ; }
#mermaid-diagram-7 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-7 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaid-diagram-7 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
#mermaid-diagram-7 .cyan&gt;rect, .cyan&gt;polygon, .cyan&gt;circle, .cyan&gt;ellipse { fill:#9ff;  stroke:#fff; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph1" transform="translate(575.75,280)" style="opacity: 1;"><rect width="1111.5" height="520" x="-555.75" y="-260"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-246" fill="black" stroke="none" id="mermaid-diagram-7Text" style="text-anchor: middle;"> PC1 Computer</text></g><g class="cluster" id="subGraph0" transform="translate(1628,327)" style="opacity: 1;"><rect width="953" height="188" x="-476.5" y="-94"></rect><g class="label"><g transform="translate(0,0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"></div></foreignObject></g></g><text x="0" y="-80" fill="black" stroke="none" id="mermaid-diagram-7Text" style="text-anchor: middle;"> Support Team</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M387.75,74.3038073038073L116,114L116,139" marker-end="url(#arrowhead595)" style="fill:none"></path><defs><marker id="arrowhead595" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M487.75,73.02950609364977L827.5,114L827.5,139" marker-end="url(#arrowhead596)" style="fill:none"></path><defs><marker id="arrowhead596" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M487.75,71.01195049082374L1023.5,114L1023.5,139" marker-end="url(#arrowhead597)" style="fill:none"></path><defs><marker id="arrowhead597" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M438.1010638297872,89L438.5,114L438.5,139" marker-end="url(#arrowhead598)" style="fill:none"></path><defs><marker id="arrowhead598" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M387.75,77.40974529346622L212,114L212,161L212,208L212,233L212,280L212,327L212,374L212,421L212,446L216.92021276595744,471" marker-end="url(#arrowhead599)" style="fill:none"></path><defs><marker id="arrowhead599" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M388.0159574468085,89L331.5,114L331.5,161L331.5,208L331.5,233L331.5,280L331.5,327L331.5,374L331.5,421L331.5,446L378.70744680851067,471" marker-end="url(#arrowhead600)" style="fill:none"></path><defs><marker id="arrowhead600" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M487.75,79.06675224646983L632.5,114L632.5,139" marker-end="url(#arrowhead601)" style="fill:none"></path><defs><marker id="arrowhead601" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1259.5,302L1259.5,327L1322.6648936170213,352" marker-end="url(#arrowhead602)" style="fill:none"></path><defs><marker id="arrowhead602" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1448.5,302L1448.5,327L1411.1329787234042,352" marker-end="url(#arrowhead603)" style="fill:none"></path><defs><marker id="arrowhead603" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1590.6702127659573,302L1548.25,327L1452.75,353.40294117647056" marker-end="url(#arrowhead604)" style="fill:none"></path><defs><marker id="arrowhead604" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1665.3297872340427,302L1707.75,327L1803.25,353.40294117647056" marker-end="url(#arrowhead605)" style="fill:none"></path><defs><marker id="arrowhead605" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1807.5,302L1807.5,327L1844.8670212765958,352" marker-end="url(#arrowhead606)" style="fill:none"></path><defs><marker id="arrowhead606" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1996.5,302L1996.5,327L1933.3351063829787,352" marker-end="url(#arrowhead607)" style="fill:none"></path><defs><marker id="arrowhead607" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M827.5,183L827.5,208L827.5,233L1186.5,272.0578703703704" marker-end="url(#arrowhead608)" style="fill:none"></path><defs><marker id="arrowhead608" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1023.5,183L1023.5,208L1023.5,233L1923.5,276.47379239465573" marker-end="url(#arrowhead609)" style="fill:none"></path><defs><marker id="arrowhead609" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1378.25,396L1378.25,421L311.5,446L263.49468085106383,471" marker-end="url(#arrowhead610)" style="fill:none"></path><defs><marker id="arrowhead610" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M1877.75,396L1877.75,421L811,446L494.75,484.0390275111964" marker-end="url(#arrowhead611)" style="fill:none"></path><defs><marker id="arrowhead611" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node cyan" id="A" transform="translate(437.75,67)" style="opacity: 1;"><rect rx="0" ry="0" x="-50" y="-22" width="100" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-40,-12)"><foreignObject width="80" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Application</div></foreignObject></g></g></g><g class="node cyan" id="B1" transform="translate(116,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-61" y="-22" width="122" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-51,-12)"><foreignObject width="102" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.public</div></foreignObject></g></g></g><g class="node cyan" id="B2" transform="translate(827.5,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="B3" transform="translate(1023.5,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="B4" transform="translate(438.5,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-72" y="-22" width="144" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62,-12)"><foreignObject width="124" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc1.secret</div></foreignObject></g></g></g><g class="node cyan" id="B5" transform="translate(221.25,493)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc1.unlock</div></foreignObject></g></g></g><g class="node cyan" id="B6" transform="translate(420.25,493)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.unlock</div></foreignObject></g></g></g><g class="node cyan" id="B7" transform="translate(632.5,161)" style="opacity: 1;"><rect rx="0" ry="0" x="-72" y="-22" width="144" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-62,-12)"><foreignObject width="124" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.secret</div></foreignObject></g></g></g><g class="node cyan" id="C1" transform="translate(1259.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="C2" transform="translate(1448.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-66" y="-22" width="132" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-56,-12)"><foreignObject width="112" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc1.json</div></foreignObject></g></g></g><g class="node cyan" id="C3" transform="translate(1628,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-63.5" y="-22" width="127" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-53.5,-12)"><foreignObject width="107" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">applock.private</div></foreignObject></g></g></g><g class="node cyan" id="C4" transform="translate(1807.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-66" y="-22" width="132" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-56,-12)"><foreignObject width="112" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.json</div></foreignObject></g></g></g><g class="node cyan" id="C5" transform="translate(1996.5,280)" style="opacity: 1;"><rect rx="0" ry="0" x="-73" y="-22" width="146" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-63,-12)"><foreignObject width="126" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.public</div></foreignObject></g></g></g><g class="node cyan" id="D1" transform="translate(1378.25,374)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user2@pc1.unlock</div></foreignObject></g></g></g><g class="node cyan" id="D2" transform="translate(1877.75,374)" style="opacity: 1;"><rect rx="0" ry="0" x="-74.5" y="-22" width="149" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-64.5,-12)"><foreignObject width="129" height="24"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">user1@pc1.unlock</div></foreignObject></g></g></g></g></g></g></svg></div>
<p>  从用户的角度来看，将发送其<code>user@host.public</code>文件，然后收到相应的<code>user@host.unlock</code>文件，该文件将解锁应用程序。很容易理解，即使场景背后涉及一些复杂的非对称加密。</p>
<h3 id="toc_18">23.3.2. 从支持团队的角度来看<a class="vnote-anchor" href="#toc_18" data-anchor-icon="#"></a></h3>
<p>  支持团队将维护一个<code>user@host.public</code>和<code>user@host.json</code>文件列表，每个计算机用户一个。这两个文件都具有较小的JSON内容，因此可以存储在项目源代码存储库的专用文件夹中，或存储在专用存储库中。源代码存储库的使用允许跟踪多个支持人员之间的用户管理信息，包括该敏感信息的历史和审计跟踪。为安全起见，<code>applock.private</code>文件可能不会在源代码存储库中存档，而是在每个支持人员（或开发人员）的计算机上有意复制。为了额外的安全性，可以使用分离的专用计算机。</p>
<p>  实际上，即使是开发人员也可以定义自己的<code>.unlock</code>文件集。对于本地测试版本，他们可以使用自己的<code>applock.public</code>和<code>applock.private</code>密钥对，这些密钥对与主要内容不同。</p>
<p>  每个<code>user@host.json</code>的内容可以很容易地从一组引用<code>.json</code>文件中推导出来，就像用户组的模板一样。或者现有文件可以用作新用户的源。使用JSON和文本编辑器以及可自定义的对象和数组字段的能力允许任何所需类型的许可或安全范围，具体取决于应用程序。</p>
<p>  由于<code>user@host.json</code>是序列化的<code>aContent: TObject</code>，因此您可以将枚举属性甚至无架构结构定义为<code>TDocVariant</code>  - 请参阅TDocVariant自定义变体类型 - 以优化授权范围。</p>
<p>  <code>user@host.json</code>文件使用正版<code>user@host.public</code>密钥加密，其关联的<code>user@host.secret</code>对给定的PC和登录用户进行了高度加密：因此，只有应用程序才能解密<code>user@host.unlock</code>内容。您可以通过不安全的传输方式传输这些文件，例如：简单的电子邮件，没有妥协的风险。最后但并非最不重要的一点是，密码或IP地址可以安全地存储在其内容中，作为项目安全策略的一部分。</p>
<p>  在实践中，团队可以使用运行<code>ECC</code>工具的<code>unlock.bat</code>文件而不是秘密的<code>applock.private</code>密钥，其中包含秘密：</p>
<pre><code class="hljs"> @echo off
 echo Usage:  unlock user@host
 echo.
 ecc sign -file %1.json -auth applock -pass applockprivatepassword -rounds 60000
 ecc crypt -file %1.json -out %1.unlock -auth %1 -saltpass decryptsalt -saltrounds 10000
 del %1.json.sign
</code></pre>
<p>  为安全起见，您可能不会在此<code>unlock.bat</code>文件中包含<code>-pass applockprivatepassword</code>值。 删除此<code>-pass</code>命令行开关将让ecc工具在控制台上提示输入密码密钥：</p>
<pre><code class="hljs"> ecc sign -file %1.json -auth applock -rounds 60000
</code></pre>
<p>  另请注意，您可以使用<code>ecc rekey</code>命令自定义给定<code>applock.private</code>文件的密码：每个支持团队成员可以使用自定义密码来运行<code>sign-then-encrypt</code>进程。</p>
<p>  当然，如果您需要创建大量<code>.unlock</code>文件，您可能希望自动执行此过程，例如在服务器或GUI工具中，使用<code>SynEcc.pas</code>类。</p>
<h3 id="toc_19">23.3.3. 非对称加密对许可证管理的好处<a class="vnote-anchor" href="#toc_19" data-anchor-icon="#"></a></h3>
<p>  在大多数许可系统中，缺点是许可文件的传输。由于非对称加密，<code>user@host.public</code>和<code>user@host.unlock</code>文件都可以作为普通电子邮件传输，不会有任何妥协的可能性。</p>
<p>  <code>applock.private</code>密钥及其相关密码用于对<code>user@host.unlock</code>文件的纯文本内容进行数字签名（使用ECDSA）。此签名然后加密模式将确保只有您的支持团队才能为给定的应用程序生成正确的<code>.unlock</code>文件。 <code>applock.private</code> / <code>public</code>键可以有自己的弃用日期。</p>
<p>  正如我们所见，<code>user@host.unlock</code>文件已加密，因此您可以使用它来传输敏感信息。其关联的<code>user@host.secret</code>密钥已在本地生成并具有到期日期 - 请参阅<code>ECCAuthorize</code>函数的<code>aSecretDays</code>参数。如果许可或安全政策期望，它将确保定期执行注册过程。</p>
<p>  当然，任何这样的系统都像它最薄弱的一样弱。特别是，在Windows下，可执行文件应进行数字签名（与任何专业软件一样）。您还可以确保<code>aAppLockPublic64</code>公钥未被攻击者伪造的伪值替换 - 例如通过在应用程序的几个位置计算其CRC来检查其值：</p>
<pre><code class="lang-pascal hljs"> <span class="hljs-keyword">if</span> crc32($<span class="hljs-number">1239438</span>,pointer(AppLock64),length(AppLock64))&lt;&gt;$ae293c10 <span class="hljs-keyword">then</span> Close;
</code></pre>
<p>  该系统的安全性不依赖于代码混淆，而是依赖于非对称加密的经证实的安全性。 即使可执行文件被就地修改以绕过许可证检查，应用程序期望在<code>user@host.unlock</code>文件中提供一些附加信息这一事实也会使攻击变得更加困难。</p>
<p>  与开源一样，欢迎任何反馈，以增强该系统的安全性。 代码可用 - 这样算法可以被证明 - 使其比在室内开发的任何专有解决方案更安全。</p>

    </div>
</div>
</div>

<div id="container-floating" style="display:none;" class="d-none d-md-block d-xl-block">
    <div id="floating-button" onclick="toggleMore()">
        <p id="floating-more" class="more">&gt;</p>
    </div>
</div>

<!--
<div class="footer" id="vnote-footer">
    <p>Generated by <em><a href="https://tamlok.github.io/vnote/">VNote</a></em>.</p>
</div>
-->
</body>
</html>
